Python SMTP email sending from entry to advanced
SMTP (Simple Mail Transfer Protocol) is the most widely used email sending standard on the Internet. Whether it is a personal mailbox, a corporate mailbox, or a server monitoring and alarm system, the bottom layer almost all relies on SMTP to deliver letters.
The Python standard library provides two core modules related to email, with clear responsibilities:
email: Responsible for assembling the content of the email, which can construct plain text, HTML, attachments, embedded images, and set email headers (sender, recipient, subject, etc.).smtplib: Responsible for sending out the assembled emails, establishing SMTP connection, login, and transmission.
This article will start from scratch and take you step by step to master using Python to send various styles of emails, and provide pitfall avoidance guides and complete examples in a production environment.
1. Preparation: Make sure your email supports SMTP
Before writing code, first ensure that the SMTP service of the mailbox is turned on and obtain the corresponding authorization information:
-
Enable SMTP service Log in to the email backend (such as QQ Mail, 163, Gmail, etc.), find the SMTP option in "Settings → Account → POP3/IMAP/SMTP Service" and turn it on.
-
Get authorization code The vast majority of third-party clients (including our Python scripts) ** cannot use login passwords directly ** and require an "authorization code" or "application-specific password" generated by email. After turning on the SMTP service, the page will usually guide you to generate it.
-
Record SMTP configuration information Different service providers have different SMTP addresses and ports. Common ports are:
- 25: Traditional clear text transmission, unsafe, most have been blocked or disabled
- 465: SSL direct connection encryption
- 587: STARTTLS encryption (recommended)
SMTP server addresses for some commonly used email addresses:
For specific information, please refer to the latest documentation from the service provider.
2. First email: plain text
2.1 Assembling email content
The simplest email is plain text and can be used directlyemail.mime.text.MIMETextto create:
MIMETextThe first parameter is the message body and the second parameter is the subtype ('plain'Represents plain text,'html'represents HTML), the third parameter specifies the character encoding, which is uniformly usedutf-8It can avoid most garbled characters.
2.2 Establish connection and send
usesmtplib.SMTPEstablish a connection and useloginMethod to log in. During the debugging phase, you can turn on the debug mode to view the complete process of SMTP protocol interaction:
Now, run this script and you can send the first email sent by a program in your life. However, the received email may look crude, without a subject or nickname. The next step is to improve it.
3. Complete the email header: Make the email look more like it was sent by a human
The above email lacks the subject, sender nickname, and recipient nickname, and looks very stiff. we can useemail.header.Headerandemail.utils.formataddrto set this information.
In order to make the code more concise, first encapsulate an "address formatting" function:
Then add to the mail objectFrom、ToandSubjecthead:
NOTE:
msg['To']Only the recipient information displayed in the email header is affected. The actual mailbox to which the email is sent is still determined bysendmailDetermined by the second parameter.
4. Advanced scenario: constructing various types of emails
4.1 HTML email
Just need to putMIMETextThe second parameter of'plain'Change to'html'That’s it:
Mail can now display rich HTML content.
4.2 Emails with attachments
To send attachments, you need to useMIMEMultipartThis "container" object.MIMEMultipartMultiple parts (text, attachments) can be combined together. The default subtype is'mixed'(mix).
Key points:
MIMEBaseUsed to represent binary data, the first parameter is the main type (application), the second is a subtype (octet-streamrepresents a binary stream).Content-Disposition: attachmentTell the client this is an attachment,filenameSpecify the file name to be displayed.- Mail transmission requires Base64 encoding,
encoders.encode_base64It can be done in one step.
4.3 Embedding local images in HTML
Internet images directly referenced in HTML emails can usually be displayed normally, but if you want to embed local images (such as company logos, charts) in the email, you need to useContent-ID(Content ID).
This way, the image is embedded in the email and no longer relies on external links.
4.4 Available in both plain text and HTML versions
Some email clients may have HTML display turned off or not load remote resources by default for security reasons. For the sake of compatibility, we should provide both plain text and HTML versions, allowing the client to choose the appropriate display method.
At this time it is necessary to useMIMEMultipart('alternative'). It will contain body text in two formats, with the email client showing the last recognized part first (usually HTML).
5. Security first: Encrypted SMTP connections
The default port 25 is clear text transmission, and account passwords and email content may be intercepted. Almost all email service providers now mandate encrypted connections, and there are two main ways.
5.1 STARTTLS encryption
First establish a normal SMTP connection and then callstarttls()Method to upgrade the connection to TLS encryption. A typical port is 587.
5.2 SSL/TLS direct connection
Use directlySMTP_SSLclass to establish an encrypted connection from the beginning. Commonly used port is 465.
💡 Selection suggestions:
- Try 587 + STARTTLS first, which is the latest standard recommendation;
- If the server does not support STARTTLS, then consider using port 465 SSL direct connection.
6. Pitfall avoidance guide and best practices
In actual projects, we need more robust code. The following are some key experience summaries:
-
Sensitive information is never hardcoded It is very dangerous to write authorization codes, email addresses and other information directly in plain text in the code. It is recommended to use environment variables,
.envfile or configuration center, e.g. viaos.getenv()Read. -
Add perfect exception-handling Network fluctuations, authentication failures, attachments that are too large, etc. may cause sending failures. Corresponding captures and prompts must be made.
-
Uniformly use UTF-8 encoding As long as the email content, subject, and nickname involve Chinese, they must be specified
'utf-8'Encoding, otherwise gibberish will be everywhere. -
The recipient must be an iterable object
sendmailThe second parameter requirement is an iterable object such as a list or tuple. Even if there is only one recipient, it must be written as[to_addr]。 -
Control the size of attachments Most free mailboxes limit the size of attachments to 10 to 50MB, and will be rejected if it exceeds. It is recommended to upload large files to a cloud disk and then share the link in an email.
Complete example with exception-handling
After the environment variables in the above script are configured, they can be easily integrated into monitoring, business notification and other scenarios.
7. Simple summary: object relationship of email module
Understanding the relationship between these classes will help you make the right choices when building complex emails:
- Send a single content (plain text, HTML, image): use directly
MIMEText、MIMEImagewait. - Send multiple combinations (attachments + text, embedded images + HTML): create first
MIMEMultipartcontainer, reuseattachmethod to add each section one by one. - Need to support both plain text and HTML display: use
MIMEMultipart('alternative')。
Through this tutorial, you should have mastered a full set of skills from simple plain text emails, to complex emails containing attachments, embedded images, and HTML format, to encrypted connections and exception-handling. Encapsulate what you learn into functions or classes and you can quickly apply it to actual projects. I wish you smooth sailing on your email sending journey!

