</>inexpresivo

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.

3 min read
awssespythonboto3email

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:

  1. Configuración en la consola de AWS
  2. 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:

  1. Ir a Verified identities → Create identity
  2. Seleccionar Email address e ingresar el correo de origen
  3. 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": "*"
    }
  ]
}
json

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-1
bash

Enviando correos con Python

Instalación

pip install boto3
bash

Enví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}")
python

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}")
python

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={...},
)
python

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.

Referencias