SMTP(Simple Mail Transfer Protocol)是发送电子邮件的标准协议。Python 提供了 smtplib 模块来实现 SMTP 客户端,用于发送电子邮件。本文将详细讲解如何使用 Python3 的 smtplib 模块发送电子邮件,包括基本使用方法、构建复杂邮件、附件处理、安全连接、异常处理和实际应用案例。
在深入讲解之前,了解一些基本概念是必要的:
首先,从发送一封简单的邮件开始。
要发送邮件,首先需要连接到 SMTP 服务器。
import smtplib
smtp_server = "smtp.example.com" # 替换为您的 SMTP 服务器地址
port = 587 # 使用适当的端口号
sender_email = "[email protected]" # 发送方邮箱地址
password = "your_password" # 发送方邮箱密码
# 创建 SMTP 客户端会话对象
server = smtplib.SMTP(smtp_server, port)
连接到 SMTP 服务器后,需要进行身份验证。
server.starttls() # 启用安全加密
server.login(sender_email, password) # 登录 SMTP 服务器
登录成功后,可以使用 sendmail 方法发送邮件。
receiver_email = "[email protected]" # 接收方邮箱地址
message = """\
Subject: Hi there
This message is sent from Python."""
server.sendmail(sender_email, receiver_email, message)
print("Email sent successfully.")
邮件发送完成后,需要关闭与 SMTP 服务器的连接。
server.quit()
完整示例代码如下:
import smtplib
smtp_server = "smtp.example.com"
port = 587
sender_email = "[email protected]"
password = "your_password"
server = smtplib.SMTP(smtp_server, port)
server.starttls()
server.login(sender_email, password)
receiver_email = "[email protected]"
message = """\
Subject: Hi there
This message is sent from Python."""
server.sendmail(sender_email, receiver_email, message)
print("Email sent successfully.")
server.quit()
使用 email 模块可以构建带有 HTML 内容、附件等复杂邮件。
首先,使用 email.mime.multipart 和 email.mime.text 构建 HTML 邮件。
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
message = MIMEMultipart("alternative")
message["Subject"] = "HTML Email"
message["From"] = sender_email
message["To"] = receiver_email
# 创建纯文本和 HTML 内容
text = """\
Hi,
This is a plain text version of the email."""
html = """\
Hi,
This is an HTML version of the email.
"""
# 将内容附加到 MIMEMultipart 对象
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
message.attach(part1)
message.attach(part2)
使用 send_message 方法发送邮件。
server.send_message(message)
完整示例代码如下:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
smtp_server = "smtp.example.com"
port = 587
sender_email = "[email protected]"
password = "your_password"
receiver_email = "[email protected]"
server = smtplib.SMTP(smtp_server, port)
server.starttls()
server.login(sender_email, password)
message = MIMEMultipart("alternative")
message["Subject"] = "HTML Email"
message["From"] = sender_email
message["To"] = receiver_email
text = """\
Hi,
This is a plain text version of the email."""
html = """\
Hi,
This is an HTML version of the email.
"""
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
message.attach(part1)
message.attach(part2)
server.send_message(message)
print("HTML email sent successfully.")
server.quit()
添加附件需要使用 email.mime.base 和 email 模块中的编码功能。
from email.mime.base import MIMEBase
from email import encoders
# 创建一个 MIMEBase 对象
part = MIMEBase("application", "octet-stream")
# 读取附件内容并将其附加到 MIMEBase 对象
filename = "document.pdf"
with open(filename, "rb") as attachment:
part.set_payload(attachment.read())
# 对附件进行编码并添加到邮件
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
message.attach(part)
server.send_message(message)
完整示例代码如下:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
smtp_server = "smtp.example.com"
port = 587
sender_email = "[email protected]"
password = "your_password"
receiver_email = "[email protected]"
server = smtplib.SMTP(smtp_server, port)
server.starttls()
server.login(sender_email, password)
message = MIMEMultipart()
message["Subject"] = "Email with Attachment"
message["From"] = sender_email
message["To"] = receiver_email
text = """\
Hi,
This email contains an attachment."""
message.attach(MIMEText(text, "plain"))
part = MIMEBase("application", "octet-stream")
filename = "document.pdf"
with open(filename, "rb") as attachment:
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
message.attach(part)
server.send_message(message)
print("Email with attachment sent successfully.")
server.quit()
为保证安全性,可以使用 SSL/TLS 连接到 SMTP 服务器。
import smtplib
smtp_server = "smtp.example.com"
port = 465
sender_email = "[email protected]"
password = "your_password"
server = smtplib.SMTP_SSL(smtp_server, port)
server.login(sender_email, password)
receiver_email = "[email protected]"
message = """\
Subject: Hi there
This message is sent from Python."""
server.sendmail(sender_email, receiver_email, message)
print("Secure email sent successfully.")
server.quit()
import smtplib
smtp_server = "smtp.example.com"
port = 587
sender_email = "[email protected]"
password = "your_password"
server = smtplib.SMTP(smtp_server, port)
server.starttls() # 启用安全加密
server.login(sender_email, password)
receiver_email = "[email protected]"
message = """\
Subject: Hi there
This message is sent from Python."""
server.sendmail(sender_email, receiver_email, message)
print("Secure email sent successfully.")
server.quit()
在实际应用中,处理可能发生的异常非常重要。常见的异常包括连接错误、身份验证错误等。
try:
server = smtplib.SMTP(smtp_server, port)
server.starttls()
server.login(sender_email, password)
except smtplib.SMTPConnectError as e:
print("Connection error:", e)
except smtplib.SMTPAuthenticationError as e:
print("Authentication error:", e)
6.2 捕获发送错误
try:
server.sendmail(sender_email, receiver_email, message)
except smtplib.SMTPRecipientsRefused as e:
print("Recipient refused:", e)
except smtplib.SMTPDataError as e:
print("Data error:", e)
完整示例代码如下:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
smtp_server = "smtp.example.com"
port = 587
sender_email = "[email protected]"
password = "your_password"
receiver_email = "[email protected]"
try:
server = smtplib.SMTP(smtp_server, port)
server.starttls()
server.login(sender_email, password)
message = MIMEMultipart()
message["Subject"] = "Email with Attachment"
message["From"] = sender_email
message["To"] = receiver_email
text = """\
Hi,
This email contains an attachment."""
message.attach(MIMEText(text, "plain"))
part = MIMEBase("application", "octet-stream")
filename = "document.pdf"
with open(filename, "rb") as attachment:
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
message.attach(part)
server.send_message(message)
print("Email with attachment sent successfully.")
except smtplib.SMTPConnectError as e:
print("Connection error:", e)
except smtplib.SMTPAuthenticationError as e:
print("Authentication error:", e)
except smtplib.SMTPRecipientsRefused as e:
print("Recipient refused:", e)
except smtplib.SMTPDataError as e:
print("Data error:", e)
except Exception as e:
print("An error occurred:", e)
finally:
server.quit()
以下示例展示了如何发送带有附件和 HTML 内容的邮件。
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
def send_email_with_attachment(subject, body, to_email, attachment_path):
smtp_server = "smtp.example.com"
port = 587
sender_email = "[email protected]"
password = "your_password"
try:
server = smtplib.SMTP(smtp_server, port)
server.starttls()
server.login(sender_email, password)
message = MIMEMultipart()
message["Subject"] = subject
message["From"] = sender_email
message["To"] = to_email
message.attach(MIMEText(body, "html"))
part = MIMEBase("application", "octet-stream")
with open(attachment_path, "rb") as attachment:
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {attachment_path.split('/')[-1]}",
)
message.attach(part)
server.send_message(message)
print("Email sent successfully.")
except Exception as e:
print("An error occurred:", e)
finally:
server.quit()
subject = "Test Email"
body = """\
Hi,
This is a test email with an attachment.
Regards,
Python Script
"""
to_email = "[email protected]"
attachment_path = "document.pdf"
send_email_with_attachment(subject, body, to_email, attachment_path)