当我们开发一个程序时,有时我们需要开发一些自动化的任务。执行完成后,系统会自动将结果发送电子邮件。Python使用smtplib
模块发送电子邮件,这是一个标准包。您可以直接导入。
以下所有代码亲测有效。
1.简化版发送邮件
import smtplib
from email.mime.text import MIMEText
# 构造消息内容,使用163邮箱发送邮件给QQ邮箱实测成功
email_host = 'smtp.163.com' # 邮件的smtp地址
email_user = 'xxxxxxx@163.com' # 发送方账户
email_pwd = 'xxxxxxx' # 发送方账户密码
maillist = 'xxxxxxx@qq.com' # 收件人邮箱,如果有多个账户,用英文逗号分隔
me = email_user
msg = MIMEText('hello, andy') # 电子邮件的内容
# Mintest被实例化,然后实例化为msg
msg['Subject'] = 'I am MeiMei' # 邮件主题
msg['From'] = me # 发送方账户
msg['To'] = maillist # 收件人账户列表
smtp = smtplib.SMTP(email_host, port=25) # 连接邮箱、接收邮箱地址和端口号,smtp的端口号为25
smtp.login(email_user, email_pwd) # 发件人的电子邮件帐户和密码
smtp.sendmail(me,maillist,msg.as_string()) # 参数是发送方和接收方,第三个参数是将上面发送的电子邮件的内容更改为字符串
smtp.quit() # 发送后退出smtp
print('email send success.')
2.简化版发送带有txt附件的邮件
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# 用于发送带有附件的电子邮件
# 构造消息内容,使用163邮箱发送邮件给QQ邮箱实测成功
email_host = 'smtp.163.com' # 邮件的smtp地址
email_user = 'xxxxxxx@163.com' # 发送方账户
email_pwd = 'xxxxxxx' # 发送方账户密码
maillist = 'xxxxxxx@qq.com' # 收件人邮箱,如果有多个账户,用英文逗号分隔
new_masg=MIMEMultipart()
# 构造一个可以发送附件的对象
new_masg.attach(MIMEText('There are attachments in this message'))
# 电子邮件的内容
me = email_user
# msg = MIMEText('hello') # 邮件内容
# Mintest被实例化,然后实例化为msg
new_masg['Subject'] = 'I am MeiMei' # 邮件主题
new_masg['From'] = me # 发送方账户
new_masg['To'] = maillist # 收件人账户列表
att=MIMEText(open('a.txt').read())
att["Content-Type"] = 'application/octet-stream'
# 发附件的时候一定要这样写
att["Content-Disposition"] = 'attachment; filename="a.txt"'
new_masg.attach(att)
smtp = smtplib.SMTP(email_host, port=25) # 连接邮箱、收信箱地址、端口号,smtp的端口号为25
smtp.login(email_user, email_pwd) # 发件人的电子邮件帐户和密码
smtp.sendmail(me,maillist,new_masg.as_string())
# 参数是sender和receiver,第三个是把上面发送的email的内容改成字符串
smtp.quit() # 发送后退出smtp
print('email send success.')
3.简化版发送csv文件
假如要发送csv内容,文件名位contact.csv
,内容为:
name,email,grade
Ron Obvious,my+ovious@gmail.com,B+
Killer Rabbit of Caerbannog,my+rabbit@gmail.com,A
Brian Cohen,my+brian@gmail.com,C
以下代码示例可让您向多个联系人发送个性化电子邮件。它为每个联系人循环一个带有姓名、电子邮件、等级的 CSV 文件。
通用消息在脚本的开头定义,并为 CSV 文件中的每个联系人填写其 {name}
和 {grade}
占位符,并通过与 mail 服务器的安全连接发送个性化电子邮件,如你之前看过:
import csv, smtplib, ssl
message = """Subject: Your grade
Hi {name}, your grade is {grade}"""
from_address = "my@gmail.com"
password = input("Type your password and press enter: ")
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(from_address, password)
with open("contacts_file.csv") as file:
reader = csv.reader(file)
next(reader) # 跳过标题行
for name, email, grade in reader:
server.sendmail(
from_address,
email,
message.format(name=name,grade=grade),
)
4.加强版本发送邮件
当然,我们可以把它封装成一个函数。使用时直接调用函数,传入邮箱账号密码、收件人、发件人、标题、附件和内容。
这个类没有异常处理,朋友们可以自己做异常处理。
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
class SendMail(object):
def __init__(self,username,passwd,recv,content,title,file=None,
email_host='smtp.163.com',port=25):
self.username = username # 发件人帐户
self.passwd = passwd # 发件人帐户密码
self.recv = recv # 接收电子邮件帐户
self.title = title # 电子邮件主题
self.file = file # 附件
self.content = content # 电子邮件的内容
self.email_host = email_host # smtp
self.port = port
def send_mail(self):
# 以下是发送附件的内容
msg=MIMEMultipart()
if self.file:
att = MIMEText(open(self.file).read()) # 附件可能不存在,所以您需要尝试
att["Content-Type"] = 'application/octet-stream'
# 发送附件时必须这样写
att["Content-Disposition"] = 'attachment; filename="%s"'%self.file
msg.attach(att)
# 以下是正文
msg.attach(MIMEText(self.content))
msg['Subject'] = self.title # 电子邮件主题
msg['From'] = self.username # 发送方账户
msg['To'] = self.recv # 收件人帐户列表
self.smtp=smtplib.SMTP(self.email_host,port=self.port)
# 发送邮件服务的目标
self.smtp.login(self.username,self.passwd)
self.smtp.sendmail(self.username,self.recv,msg.as_string())
def __del__(self):
self.smtp.quit()
if __name__ == '__main__':
m = SendMail(
username='xxxxxx@163.com',passwd='xxxxxxx',recv='xxxxxx@qq.com', file="a.txt",
title='This is an email from the class', content='Pan Yang is a big beauty', email_host='smtp.163.com')
m.send_mail()
5.加强版本发送带有附件(txt或者pdf)邮件
为了将二进制文件发送到旨在处理文本数据的电子邮件服务器,它们需要在传输之前进行编码。这通常使用 base64 来完成,它将二进制数据编码为可打印的 ASCII 字符。
#!/usr/bin/python3
import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.mime.base import MIMEBase
# 方法一:使用sendmail
class SendMail(object):
def __init__(self, username, passwd, recv, content, title, file=None,
email_host='smtp.163.com', port=25, content_subtype="plain"):
self.username = username # 发送方账户
self.passwd = passwd # 发送方账户密码
self.recv = recv # 接收邮件账户可以是列表
self.title = title # 邮件主题
self.file = file # 附件
self.content = content # 邮件正文
self.email_host = email_host # smtp
self.port = port
self.content_subtype = content_subtype # 正文类型 html,plain
def send_mail(self):
# 以下是发送内容的附件
msg = MIMEMultipart()
if self.file:
# 判断是txt文件还是pdf文件
if self.file.endswith(".txt"):
try:
att = MIMEText(open(self.file, mode='rb').read(), "base64", "utf-8") # 附件可能不存在,所以您需要尝试
except Exception as e:
raise Exception(f"open {self.file} Error!")
else:
att["Content-Type"] = 'application/octet-stream'
# 发送附件时必须这样写
# 附件名称非中文时的写法
# att["Content-Disposition"] = 'attachment; filename="%s"' % self.file
# 附件名称为中文时的写法
att.add_header("Content-Disposition", "attachment", filename=("gbk", "", f"{self.file}"))
msg.attach(att)
elif self.file.endswith(".pdf"):
try:
# 以二进制模式打开PDF文件
with open(self.file, "rb") as attachment:
# 添加文件作为application/octet-stream
# 电子邮件客户端通常可以自动下载此附件
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
except Exception as e:
raise Exception(f"open {self.file} Error!")
else:
# 添加头作为键/值对到附件part
# 附件名称为中文时的写法
part.add_header("Content-Disposition", "attachment", filename=("gbk", "", f"{self.file}"))
# 以 ASCII 字符编码文件以通过电子邮件发送
encoders.encode_base64(part)
# 附件名称非中文时的写法
# part.add_header(
# "Content-Disposition",
# f"attachment; filename= {self.file}",
# )
# 向消息添加附件
msg.attach(part)
# 以下是正文
msg.attach(MIMEText(self.content, self.content_subtype))
msg['Subject'] = self.title # 电子邮件主题
msg['From'] = self.username # 发送方账户
msg['To'] = self.recv # 收件人帐户列表
msg["Bcc"] = self.recv # 群发电子邮件推荐
self.smtp = smtplib.SMTP(self.email_host, port=self.port)
# 发送邮件服务的目标
self.smtp.login(self.username, self.passwd)
self.smtp.sendmail(self.username, self.recv, msg.as_string())
def __del__(self):
self.smtp.quit()
# 方法二:使用SMTP_SSL
class SendMailSSL(object):
def __init__(self, username, passwd, recv, content, title, file=None,
email_host='smtp.163.com', port=465, content_subtype="plain"):
self.username = username # 发送方账户
self.passwd = passwd # 发送方账户密码
self.recv = recv # 接收邮件账户可以是列表
self.title = title # 邮件主题
self.file = file # 附件
self.content = content # 邮件正文
self.email_host = email_host # smtp
self.port = port
self.content_subtype = content_subtype # 正文类型 html,plain
def send_mail(self):
# 以下是发送内容的附件
msg = MIMEMultipart()
if self.file:
if self.file.endswith(".txt"):
try:
att = MIMEText(open(self.file, "rb").read(), "base64", "utf-8") # 附件可能不存在,所以您需要尝试
except Exception as e:
raise Exception(f"open {self.file} Error!")
else:
att["Content-Type"] = 'application/octet-stream'
# 发送附件时必须这样写
# 附件名称非中文时的写法
# att["Content-Disposition"] = 'attachment; filename="%s"' % self.file
# 附件名称为中文时的写法
att.add_header("Content-Disposition", "attachment", filename=("gbk", "", f"{self.file}"))
msg.attach(att)
elif self.file.endswith(".pdf"):
try:
# 以二进制模式打开PDF文件
with open(self.file, "rb") as attachment:
# 添加文件作为 application/octet-stream
# 电子邮件客户端通常可以将其作为附件自动下载
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
except Exception as e:
raise Exception(f"open {self.file} Error!")
else:
# 添加头作为键/值对到附件part
# 附件名称为中文时的写法
part.add_header("Content-Disposition", "attachment", filename=("gbk", "", f"{self.file}"))
# Encode file in ASCII characters to send by email
encoders.encode_base64(part)
# 附件名称非中文时的写法
# part.add_header(
# "Content-Disposition",
# f"attachment; filename= {self.file}",
# )
# 向消息添加附件
msg.attach(part)
# 以下是正文
msg.attach(MIMEText(self.content, self.content_subtype))
msg['Subject'] = self.title # 电子邮件主题
msg['From'] = self.username # 发送方账户
msg['To'] = self.recv # 收件人帐户列表
msg["Bcc"] = self.recv # 群发电子邮件推荐
context = ssl.create_default_context()
with smtplib.SMTP_SSL(self.email_host, port=self.port, context=context) as self.smtp:
# 发送邮件服务的目标
self.smtp.login(self.username, self.passwd)
self.smtp.sendmail(self.username, self.recv, msg.as_string())
if __name__ == '__main__':
# 使用方法一SendMail
m = SendMail(
username='xxxx@163.com', passwd='xxxx', recv='xxxxx@qq.com', file="xxx.txt",
title='This is an email from the class demo', content='LULU is a big beauty', email_host='smtp.163.com')
m.send_mail()
# 使用方法二SendMailSSL
content = """\
Subject: Hi there
This message is sent from Python."""
text = """\
Hi,
How are you?
Real Python has many great tutorials:
www.realpython.com"""
html = """\
<html>
<body>
<p>Hi,<br>
How are you?<br>
<a href="http://www.realpython.com">Real Python</a>
has many great tutorials.
</p>
</body>
</html>
"""
m_ssl = SendMailSSL(
username='xxxxxx@163.com', passwd='xxxxxx', recv='xxxxx@qq.com', file="xxxx.pdf",
title='This is an email from the class demo', content=html, email_host='smtp.163.com', content_subtype="html")
m_ssl.send_mail()
参考目录
https://www.programmerall.com/article/2177239137/
https://realpython.com/python-send-email/