I am using django-ses==3.4.1
to send email via django.core.mail
and both send_mail()
and EmailMessage()
get the connection timeout after one minute:
botocore.exceptions.ConnectTimeoutError: Connect timeout on endpoint URL: "https://email-smtp.eu-central-1.amazonaws.com/
Using this configuration in settings.py
according to the instructions on https://pypi.org/project/django-ses/
EMAIL_BACKEND = 'django_ses.SESBackend'
AWS_SES_USER = 'my-verified@email'
AWS_SES_ACCESS_KEY_ID = '-my-access-key-'
AWS_SES_SECRET_ACCESS_KEY = '-my-secret-access-key-'
AWS_SES_REGION_NAME = 'eu-central-1'
AWS_SES_REGION_ENDPOINT = 'email-smtp.eu-central-1.amazonaws.com'
Where I use the variable AWS_SES_USER
as from_email
while calling
email = EmailMessage(subject, message, from_email, recipient_list)
email.content_subtype = 'html'
email.send()
I have also tested if the SES works without Django, i.e. simply using smtplib
and it does.
The working example derived from https://realpython.com/python-send-email/#option-2-using-starttls
smtp_server = "email-smtp.eu-central-1.amazonaws.com"
port = 587
# Create a secure SSL context
context = ssl.create_default_context()
# Try to log in to server and send email
try:
server = smtplib.SMTP(smtp_server,port)
server.ehlo() # Can be omitted
server.starttls(context=context) # Secure the connection
server.ehlo() # Can be omitted
server.login(AWS_SES_ACCESS_KEY_ID, AWS_SES_SECRET_ACCESS_KEY)
message = """\
Subject: Test SES
This message is sent from Python."""
receiver_email = 'my-recipient@email'
server.sendmail(AWS_SES_USER, receiver_email, message)
I have tried changing the parameters in settings.py
in many ways, but without success.
Eventually, the working solution without django-ses
is simple. However, you have to replace the EmailMessage()
with your own function containing the working example mentioned in the question.
Include the following in settings.py:
EMAIL_BACKEND = 'django_ses.SESBackend'
EMAIL_PORT = 587 # TLS=587, SSL=465
AWS_SES_USER = 'my-verified@email'
AWS_SES_ACCESS_KEY_ID = '-my-access-key-'
AWS_SES_SECRET_ACCESS_KEY = '-my-secret-access-key-'
AWS_SES_REGION_NAME = 'eu-central-1'
AWS_SES_REGION_ENDPOINT = 'email-smtp.eu-central-1.amazonaws.com'
Then, you write the send_mail_ses()
function in a file (e.g. emailer.py) that you will call from your view (e.g. from views.py):
from django.conf.settings import EMAIL_BACKEND, EMAIL_PORT, \
AWS_SES_USER, AWS_SES_ACCESS_KEY_ID, \
AWS_SES_REGION_ENDPOINT, \
AWS_SES_SECRET_ACCESS_KEY
def send_mail_ses(request, data):
message = MIMEMultipart("alternative")
message["Subject"] = data['subject']
message["From"] = data.get('from', AWS_SES_USER)
message["To"] = data.get('to')
part = MIMEText(data['message'], data['how'])
message.attach(part)
context = ssl.create_default_context()
try:
server = smtplib.SMTP(AWS_SES_REGION_ENDPOINT, EMAIL_PORT)
server.ehlo() # Can be omitted
server.starttls(context=context) # Secure the connection
server.ehlo() # Can be omitted
server.login(AWS_SES_ACCESS_KEY_ID, AWS_SES_SECRET_ACCESS_KEY)
receiver_email = message["To"]
server.sendmail(
AWS_SES_USER, receiver_email, message.as_string()
)
server.quit()
return HttpResponse(status=204)
except Exception as err:
server.quit() # handle failure
return HttpResponse(status=500)
Note that you can handle the HttpResponse
and any errors as you prefer.
Then, you have two options for formatting the message before sending: plain or html.
With the plain text, you define the data
dictionary and pass it to the send_mail_ses()
function:
message = "This is the email message."
data = {
'how': 'plain',
'subject': f"This is the subject",
'message': message_text,
'from': AWS_SES_USER,
'to': '[email protected]',
}
send_mail_ses(request, data)
With the html formatted:
context = {'message_text': message_text}
html_message = render_to_string("email_template.html", context)
data = {
'how': 'html',
'subject': f"This is the subject",
'message': html_message,
'from': AWS_SES_USER,
'to': '[email protected]',
}
send_mail_ses(request, data)
In this case you will have to inject the {{message_text}}
from the context into the email_template.html template.
Note: this is untested because it is an extract out of my much more complex code.