Send HTML Email With Attachments via SMTP
Starting from Python 3.6, the standard library includes the email
package to build email messages (which may eventually contain HTML code and attachments) and the smtplib
module to send them through the SMTP protocol, with the possibility of using secure SSL and TLS connections. In this post we will learn how to build and send an email in Python through any SMTP server (Gmail, Outlook, Yahoo, etc. or a custom SMTP service).
Let's start by sending a plain text email. The first step is to import the necessary modules. The email
package has several modules (email.message
, email.parser
, etc.) to work with emails. We are only interested in email.message
, which contains the necessary class (EmailMessage
) to create an email. On the other hand, we will need the smtplib
module to send it through an SMTP server once the message has been created.
Next, let's define three variables to store the email sender and recipient, and the message itself (in plain text or HTML).
You will need to replace the content of sender
and recipient
with the actual email addresses. If you're using a service like Gmail, Outlook, or Yahoo, make sure to put in the sender
variable the email address of the account you want to send the message from.
Now let's use this data to build the message via the email.message.EmailMessage
class:
|
email = EmailMessage()
|
|
email["From"] = sender
|
|
email["To"] = recipient
|
|
email["Subject"] = "Sent from Python!"
|
|
email.set_content(message)
|
The email
instance is like a dictionary in which the "From"
(wherefrom the message is sent), "To"
(where it is sent to) and "Subject"
keys are defined. By default, the set_content()
method, which defines the body of the email, assumes that the message passed as an argument is plain text.
Once the email has been created, we must send it through one of the many existing protocols. In this case we will use SMTP with the help of the standard module smtplib
. The first thing to do is to connect to the proper server (typically a domain, such as smtp.gmail.com
or smtp.example.com
, or an IP address).
Check your email provider's documentation for the exact SMTP server address. The smtplib.SMTP
class establishes an insecure connection by default. The default port is 25. However, virtually all modern SMTP servers will require a secure connection using SSL or TLS. If your email provider requires TLS, use this code instead:
|
# The port of the TLS protocol is usually 587.
|
|
smtp = smtplib.SMTP("smtp.example.com", port=587)
|
|
# Start the secure connection via TLS.
|
|
smtp.starttls()
|
If the SMTP server requires a secure connection via SSL (instead of TLS), then we must use the smtplib.SMTP_SSL
class (thus the starttls()
call is not necessary):
The smtplib.SMTP_SSL
class uses port 465 by default, which is the one normally used for SSL connections. Many email servers (such as Gmail) support SSL and TLS interchangeably, so either of the two previous codes will work.
Once the connection to the SMTP server is established, we must authenticate with our credentials (username and password) and send the built email.
The user that is passed as an argument to the login()
method is usually the same email address from which we send the message, stored in sender
. In services like Gmail, Outlook or Yahoo, the password passed as the second argument is the same as your account password. The sendmail()
method is responsible for sending the email to the recipient. Finally, we close the connection to the server via the quit()
method.
Full code:
Sending a HTML Email¶
In order to include HTML code in an email, just add the subtype="html"
argument when defining the email body via the set_content()
method.
Attachments¶
We can attach files to an email by calling the add_attachment()
method as many times as needed. For example, if we want to attach the file attachment.zip
, after setting the body of the message we will do the following:
|
with open("attachment.zip", "rb") as f:
|
|
email.add_attachment(
|
|
f.read(),
|
|
filename="attachment.zip",
|
|
maintype="application",
|
|
subtype="zip"
|
|
)
|
filename="attachment.zip"
defines the name that the file will have in the email, which may differ from the original file name as read via the open()
function. The maintype
and subtype
arguments define the type of the file according to the MIME specification. You can see a list of valid values for these two arguments at https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types. So, for example, if the MIME type for .zip
files is application/zip
(according to the list in the previous link), then maintype
should be "application"
and subtype
should be "zip"
.
Full code: