Python实现SMTP邮件发送:纯文本、HTML、附件及图片详解

夏知夏
夏知夏
发布时间:2026-10-13 | 2人浏览过
原创

本文详解Python基于SMTP协议发送电子邮件的完整实现。涵盖纯文本、HTML格式、带附件及嵌入图片邮件的构造方法。通过smtplib与email模块配合,结合网易163邮箱实例,提供客户端授权密码配置、消息体构建及sendmail调用的具体代码示例,帮助开发者掌握Python邮件自动化发送技能。

本文通过具体实例介绍如何利用Python基于SMTP协议实现邮件发送功能,供读者参考学习。

SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)规定了从源地址到目的地址传送邮件的规则,控制信件的中转方式。Python内置了对SMTP的支持,能够发送纯文本邮件、HTML邮件以及带有附件的邮件。

Python对SMTP的支持主要依赖于smtplib和email两个模块。其中,email模块负责构造邮件内容,而smtplib模块负责执行实际的发送操作。

在Python中创建SMTP对象的语法如下所示:

import smtplib
smtpObj = mstplib.SMTP(host,port)

若需创建支持SSL协议的SMTP连接,请使用以下代码:

import smtplib
smtpObj = mstplib.SMTP_SSL(host,port)

利用SMTP对象发送邮件的具体调用方式如下:

# from_addr:发送者邮箱
# to_addrs:接收者邮箱,list
# msg:消息体
smtpObj.sendmail(from_addr, to_addrs, msg, mail_options=[],
         rcpt_options=[])

以下示例均以网易邮箱作为邮件服务器进行演示,网易163免费邮箱的相关服务器配置信息如下:

使用网易邮箱作为发送方时需注意,登录时使用的密码并非邮箱的网页登录密码,而是需要在邮箱设置中开启客户端授权后生成的“客户端授权密码”。

发送纯文本邮件

首先,我们需要构造消息体,代码如下:

from email.header import Header
from email.mime.text import MIMEText
# 第一个参数为邮件正文,第二个参数为MINE的subtype,传入‘plain',最终的MINE就是‘text/plain',最后参数为编码
msg = MIMEText('hello email','palin','utf-8')
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
# 发送者昵称
msg['From'] = _format_addr('发送者昵称 <%s>'%from_addr) 
# 接收者昵称
msg['To'] = _format_addr('接收者昵称 <%s>'%to_addr)
# 标题
msg['Subject'] = Header('标题','utf-8').encode()

上述代码构建了一个简单的消息体。需要特别注意的是,如果未指定标题及发件人昵称,或未进行正确的格式化编码,邮件极有可能被识别为垃圾邮件从而导致发送失败。

以下是发送纯文本邮件的完整示例代码:

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.utils import formataddr,parseaddr
host = 'smtp.163.com'
port = 25
from_addr = 'xxxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxxx@qq.com'
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
msg = MIMEText('hello email','palin','utf-8')
msg['From'] = _format_addr('发送者昵称 <%s>'%from_addr) 
msg['To'] = _format_addr('接收者昵称 <%s>'%to_addr)
msg['Subject'] = Header('标题','utf-8').encode()
smtpObj = smtplib.SMTP(host,25)
smtpObj.set_debuglevel(1)
smtpObj.login(sender,password)
smtpObj.sendmail(sender, [receivers], message.as_string())
smtoObj.quit()

值得注意的是,在调用sendmail方法时,接收者邮箱参数为列表(list)类型,这一设计支持群发功能。

发送HTML邮件

若有发送HTML格式邮件的需求,我们仍需先构造一个MIMEText对象,并将HTML字符串传入,示例如下:

htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>Hello SMTP</h1>
  <p>点击<a href="https://www.baidu.com" rel="external nofollow" rel="external nofollow" >链接</a></p>
</body>
</html>'''
msg = MIMEText(htmlStr,'html','utf-8')

发送HTML邮件的完整代码如下:

import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr,parseaddr
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
server = 'smtp.163.com'
from_addr = 'xxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxx1@qq.com'
htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>Hello SMTP</h1>
  <p>点击<a href="https://www.baidu.com" rel="external nofollow" rel="external nofollow" >链接</a></p>
</body>
</html>'''
msg = MIMEText(htmlStr,'html','utf-8')
msg['From'] = _format_addr("发送者 <%s>"%from_addr)
msg['To'] = _format_addr("接收者 <%s>"%to_addr)
msg['Subject'] = Header('一个简单的标题','utf-8').encode()
smtpObj = smtplib.SMTP(server,25)
smtpObj.set_debuglevel(1)
smtpObj.login(from_addr,from_addr_pwd)
smtpObj.sendmail(from_addr,[to_addr],msg.as_string())
smtpObj.quit()

发送附件邮件

若需发送包含附件的邮件,应如何改造消息体?此时可使用MIMEMultipart来构造邮件主体,传递一个MIMEText对象以写入邮件正文,再利用MIMEBase对象存储附件信息,代码如下:

msg = MIMEMultipart()
msg.attach(MIMEText('发送一个附件...','plain','utf-8'))
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  # 设置附件的MIME
  mime = MIMEBase('image','png',filename='1.png')
  # 加上必要的头信息
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  # 读取文件内容
  mime.set_payload(f.read())
  # 使用base64编码
  encode_base64(mime)
  msg.attach(mime)

发送附件邮件的完整示例代码如下:

import smtplib,os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart,MIMEBase
from email.header import Header
from email.encoders import encode_base64
from email.utils import formataddr,parseaddr
msg = MIMEMultipart()
msg.attach(MIMEText('发送一个附件...','plain','utf-8'))
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
server = 'smtp.163.com'
from_addr = 'xxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxx1@qq.com'
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  mime = MIMEBase('image','png',filename='1.png')
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  mime.set_payload(f.read())
  encode_base64(mime)
  msg.attach(mime)
msg['From'] = _format_addr("发送者 <%s>"%from_addr)
msg['To'] = _format_addr("接收者 <%s>"%to_addr)
msg['Subject'] = Header('一个简单的附件邮件','utf-8').encode()
smtpObj = smtplib.SMTP(server,25)
smtpObj.set_debuglevel(1)
smtpObj.login(from_addr,from_addr_pwd)
smtpObj.sendmail(from_addr,[to_addr],msg.as_string())
smtpObj.quit()

发送图片邮件

若需在文本中插入图片作为邮件正文,有人可能想到直接在HTML中使用img标签引用图片路径。但这种方式存在一个问题:无法直接发送本地图片文件。解决方法是结合HTML与附件发送方式:先将图片作为附件添加,然后在HTML的img标签中引用src='cid:0',即可将图片嵌入邮件正文,具体实现如下:

msg = MIMEMultipart()
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  mime = MIMEBase('image','png',filename='1.png')
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  mime.set_payload(f.read())
  encode_base64(mime)
  msg.attach(mime)
htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>图片标题</h1>
  <p>插入一个图片<img src="cid:0"/></p>
</body>
</html>'''
msg.attach(MIMEText(htmlStr,'html','utf-8'))

发送图片邮件的完整代码如下:

import smtplib,os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart,MIMEBase
from email.header import Header
from email.encoders import encode_base64
from email.utils import parseaddr,formataddr
server = 'smtp.163.com'
from_addr = 'xxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxx1@qq.com'
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
msg = MIMEMultipart()
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  # 设置附件的MIME
  mime = MIMEBase('image','png',filename='1.png')
  # 加上必要的头信息
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  # 读取文件内容
  mime.set_payload(f.read())
  # 使用base64编码
  encode_base64(mime)
  msg.attach(mime)
htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>图片标题</h1>
  <p>插入一个图片<img src="cid:0"/></p>
</body>
</html>'''
msg.attach(MIMEText(htmlStr,'html','utf-8'))
msg['From'] = _format_addr('发送者 <%s>'%from_addr)
msg['To'] = _format_addr('接收者 <%s>'%to_addr)
msg['Subject'] = Header('发送图片邮件','utf-8').encode()
smtpObj = smtplib.SMTP(server,25)
smtpObj.set_debuglevel(1)
smtpObj.login(from_addr,from_addr_pwd)
smtpObj.sendmail(from_addr,[to_addr],msg.as_string())
smtpObj.quit()

若需发送多个图片,可依次对它们进行编号,并在HTML中引用不同的cid:x即可实现。

更多关于Python的相关内容,可查看本站专题:《Python Socket编程技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》。

希望本文所述的Python邮件发送方法对大家有所帮助。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表