Cómo enviar correos con AWS Simple Email Service (SES)
Tutorial para enviar correos con Amazon SES usando el SDK de Python (boto3). Configuración en consola y código completo de envío.
En este tutorial vamos a enviar correos con Simple Email Service (SES) de AWS usando el SDK para Python (boto3). El proceso se divide en dos partes:
- Configuración en la consola de AWS
- Código Python para enviar correos
Configuración en AWS
1. Verificar el correo de origen
Antes de enviar cualquier correo, SES requiere que el dominio o la dirección de origen esté verificada. En la consola de SES:
- Ir a Verified identities → Create identity
- Seleccionar Email address e ingresar el correo de origen
- SES enviará un enlace de confirmación a esa dirección — hacer click para verificar
Mientras la cuenta esté en sandbox, también se necesita verificar la dirección de destino de la misma forma.
2. Crear credenciales IAM
Necesitamos un usuario o rol con permisos para SES. La política mínima necesaria:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
}
]
}Con las credenciales listas, configurar AWS CLI o exportar las variables de entorno:
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=us-east-1Enviando correos con Python
Instalación
pip install boto3Envío simple de texto plano
import boto3
from botocore.exceptions import ClientError
def send_email(sender: str, recipient: str, subject: str, body_text: str) -> str:
client = boto3.client("ses", region_name="us-east-1")
try:
response = client.send_email(
Source=sender,
Destination={
"ToAddresses": [recipient],
},
Message={
"Subject": {
"Data": subject,
"Charset": "UTF-8",
},
"Body": {
"Text": {
"Data": body_text,
"Charset": "UTF-8",
},
},
},
)
except ClientError as e:
print(f"Error: {e.response['Error']['Message']}")
raise
return response["MessageId"]
if __name__ == "__main__":
message_id = send_email(
sender="remitente@tudominio.com",
recipient="destinatario@ejemplo.com",
subject="Prueba SES",
body_text="Este correo fue enviado con Amazon SES y boto3.",
)
print(f"Correo enviado. MessageId: {message_id}")Envío con HTML y texto plano (recomendado)
Para mayor compatibilidad se envía tanto la versión HTML como la de texto plano. Los clientes de correo que no soportan HTML mostrarán el texto:
import boto3
from botocore.exceptions import ClientError
CHARSET = "UTF-8"
def send_html_email(
sender: str,
recipient: str,
subject: str,
body_text: str,
body_html: str,
) -> str:
client = boto3.client("ses", region_name="us-east-1")
try:
response = client.send_email(
Source=sender,
Destination={
"ToAddresses": [recipient],
},
Message={
"Subject": {"Data": subject, "Charset": CHARSET},
"Body": {
"Text": {"Data": body_text, "Charset": CHARSET},
"Html": {"Data": body_html, "Charset": CHARSET},
},
},
)
except ClientError as e:
print(f"Error: {e.response['Error']['Message']}")
raise
return response["MessageId"]
if __name__ == "__main__":
html_body = """
<html>
<body>
<h1>Bienvenido</h1>
<p>Este correo fue enviado con <strong>Amazon SES</strong> y boto3.</p>
</body>
</html>
"""
text_body = "Bienvenido\n\nEste correo fue enviado con Amazon SES y boto3."
message_id = send_html_email(
sender="remitente@tudominio.com",
recipient="destinatario@ejemplo.com",
subject="Bienvenido",
body_text=text_body,
body_html=html_body,
)
print(f"MessageId: {message_id}")Enviando a múltiples destinatarios
response = client.send_email(
Source="remitente@tudominio.com",
Destination={
"ToAddresses": ["a@ejemplo.com", "b@ejemplo.com"],
"CcAddresses": ["cc@ejemplo.com"],
"BccAddresses": ["bcc@ejemplo.com"],
},
Message={...},
)Siguiente paso
Una vez configurado el envío, el paso natural es manejar los rebotes y quejas que SES genera. Esto se hace integrando SES con SNS para recibir notificaciones de Bounce, Complaint y Delivery. Ver: Cómo conectar SNS con SES en Python.