我有问题理解如何使用Python电子邮件附件。我已经成功地通过smtplib电子邮件发送了简单的消息。有人能解释一下如何在电子邮件中发送附件吗?我知道网上还有其他的帖子,但作为一个Python初学者,我发现它们很难理解。
当前回答
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import smtplib
msg = MIMEMultipart()
password = "password"
msg['From'] = "from_address"
msg['To'] = "to_address"
msg['Subject'] = "Attached Photo"
msg.attach(MIMEImage(file("abc.jpg").read()))
file = "file path"
fp = open(file, 'rb')
img = MIMEImage(fp.read())
fp.close()
msg.attach(img)
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
server.login(msg['From'], password)
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()
其他回答
其他的答案也很好,但我还是想分享一种不同的方法,以防有人正在寻找替代方案。
主要的区别是,使用这种方法,你可以使用HTML/CSS来格式化你的邮件,所以你可以有创意,给你的电子邮件一些样式。虽然没有强制使用HTML,但仍然可以只使用纯文本。
注意,该函数接受将电子邮件发送给多个收件人,也允许附加多个文件。
我只在python2上尝试过,但我认为它在python3上也能正常工作:
import os.path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
def send_email(subject, message, from_email, to_email=[], attachment=[]):
"""
:param subject: email subject
:param message: Body content of the email (string), can be HTML/CSS or plain text
:param from_email: Email address from where the email is sent
:param to_email: List of email recipients, example: ["a@a.com", "b@b.com"]
:param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
"""
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ", ".join(to_email)
msg.attach(MIMEText(message, 'html'))
for f in attachment:
with open(f, 'rb') as a_file:
basename = os.path.basename(f)
part = MIMEApplication(a_file.read(), Name=basename)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename
msg.attach(part)
email = smtplib.SMTP('your-smtp-host-name.com')
email.sendmail(from_email, to_email, msg.as_string())
我希望这能有所帮助!: -)
下面是Python 3.6及更新版本的更新版本,使用Python标准库中经过大修的电子邮件模块的EmailMessage类。
import mimetypes
import os
import smtplib
from email.message import EmailMessage
username = "user@example.com"
password = "password"
smtp_url = "smtp.example.com"
port = 587
def send_mail(subject: str, send_from: str, send_to: str, message: str, directory: str, filename: str):
# Create the email message
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = send_from
msg['To'] = send_to
# Set email content
msg.set_content(message)
path = directory + filename
if os.path.exists(path):
ctype, encoding = mimetypes.guess_type(path)
if ctype is None or encoding is not None:
# No guess could be made, or the file is encoded (compressed), so
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
# Add email attachment
with open(path, 'rb') as fp:
msg.add_attachment(fp.read(),
maintype=maintype,
subtype=subtype,
filename=filename)
smtp = smtplib.SMTP(smtp_url, port)
smtp.starttls() # for using port 587
smtp.login(username, password)
smtp.send_message(msg)
smtp.quit()
你可以在这里找到更多的例子。
下面是Oli为python3编写的修改版本
import smtplib
from pathlib import Path
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders
def send_mail(send_from, send_to, subject, message, files=[],
server="localhost", port=587, username='', password='',
use_tls=True):
"""Compose and send email with provided info and attachments.
Args:
send_from (str): from name
send_to (list[str]): to name(s)
subject (str): message title
message (str): message body
files (list[str]): list of file paths to be attached to email
server (str): mail server host name
port (int): port number
username (str): server auth username
password (str): server auth password
use_tls (bool): use TLS mode
"""
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(message))
for path in files:
part = MIMEBase('application', "octet-stream")
with open(path, 'rb') as file:
part.set_payload(file.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename={}'.format(Path(path).name))
msg.attach(part)
smtp = smtplib.SMTP(server, port)
if use_tls:
smtp.starttls()
smtp.login(username, password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.quit()
这里目前给出的答案都不能正确地与GMail、Outlook 2016等客户机的文件名中的非ascii符号一起工作,以及其他不支持RFC 2231的客户机(例如,参见这里)。下面的Python 3代码改编自其他一些stackoverflow的答案(对不起,没有保存原始链接)和Python 2.7的odoo/openerp代码(参见ir_mail_server.py)。它可以正确地与GMail和其他设备一起工作,并且还使用SSL。
import smtplib, ssl
from os.path import basename
from email.mime.base import MIMEBase
from mimetypes import guess_type
from email.encoders import encode_base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email.charset import Charset
def try_coerce_ascii(string_utf8):
"""Attempts to decode the given utf8-encoded string
as ASCII after coercing it to UTF-8, then return
the confirmed 7-bit ASCII string.
If the process fails (because the string
contains non-ASCII characters) returns ``None``.
"""
try:
string_utf8.encode('ascii')
except UnicodeEncodeError:
return
return string_utf8
def encode_header_param(param_text):
"""Returns an appropriate RFC 2047 encoded representation of the given
header parameter value, suitable for direct assignation as the
param value (e.g. via Message.set_param() or Message.add_header())
RFC 2822 assumes that headers contain only 7-bit characters,
so we ensure it is the case, using RFC 2047 encoding when needed.
:param param_text: unicode or utf-8 encoded string with header value
:rtype: string
:return: if ``param_text`` represents a plain ASCII string,
return the same 7-bit string, otherwise returns an
ASCII string containing the RFC2047 encoded text.
"""
if not param_text: return ""
param_text_ascii = try_coerce_ascii(param_text)
return param_text_ascii if param_text_ascii\
else Charset('utf8').header_encode(param_text)
smtp_server = '<someserver.com>'
smtp_port = 465 # Default port for SSL
sender_email = '<sender_email@some.com>'
sender_password = '<PASSWORD>'
receiver_emails = ['<receiver_email_1@some.com>', '<receiver_email_2@some.com>']
subject = 'Test message'
message = """\
Hello! This is a test message with attachments.
This message is sent from Python."""
files = ['<path1>/файл1.pdf', '<path2>/файл2.png']
# Create a secure SSL context
context = ssl.create_default_context()
msg = MIMEMultipart()
msg['From'] = sender_email
msg['To'] = COMMASPACE.join(receiver_emails)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(message))
for f in files:
mimetype, _ = guess_type(f)
mimetype = mimetype.split('/', 1)
with open(f, "rb") as fil:
part = MIMEBase(mimetype[0], mimetype[1])
part.set_payload(fil.read())
encode_base64(part)
filename_rfc2047 = encode_header_param(basename(f))
# The default RFC 2231 encoding of Message.add_header() works in Thunderbird but not GMail
# so we fix it by using RFC 2047 encoding for the filename instead.
part.set_param('name', filename_rfc2047)
part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)
msg.attach(part)
with smtplib.SMTP_SSL(smtp_server, smtp_port, context=context) as server:
server.login(sender_email, sender_password)
server.sendmail(sender_email, receiver_emails, msg.as_string())
我知道这是一个老问题,但我认为一定有一种比其他例子更简单的方法来做到这一点,因此我做了一个库,在不污染代码库的情况下干净地解决这个问题。包含附件非常简单:
from redmail import EmailSender
from pathlib import Path
# Configure an email sender
email = EmailSender(
host="<SMTP HOST>", port=0,
user_name="me@example.com", password="<PASSWORD>"
)
# Send an email
email.send(
sender="me@example.com",
receivers=["you@example.com"],
subject="An example email"
attachments={
"myfile.txt": Path("path/to/a_file.txt"),
"myfile.html": "<h1>Content of a HTML attachment</h1>"
}
)
你也可以直接附加字节,Pandas DataFrame(根据键中的文件扩展名转换为格式),Matplotlib图或枕头图像。这个库很可能是你需要一个电子邮件发送者的所有功能(它比附件要多得多)。
如何安装:
pip install redmail
你喜欢怎么用就怎么用。我还写了大量的文档:https://red-mail.readthedocs.io/en/latest/
推荐文章
- 如何禁用标准错误流的日志记录?
- 用Matplotlib在Python中绘制时间
- 类中的Python装饰器
- 在Python中锁定文件
- 得到熊猫栏目的总数
- 从pandas DataFrame中删除名称包含特定字符串的列
- Mock vs MagicMock
- 如何阅读一个。xlsx文件使用熊猫库在iPython?
- 如何访问熊猫组由数据帧按键
- Pandas和NumPy+SciPy在Python中的区别是什么?
- 将列表转换为集合会改变元素的顺序
- 如何在matplotlib更新一个情节
- TypeError: ` NoneType `对象在Python中不可迭代
- 如何在Vim注释掉一个Python代码块
- python标准库中的装饰符(特别是@deprecated)