'How to save sent email with attachment
I wrote an agent to send emails with smtp server.
All is ok about sending, but I would like to save an .eml file that contains not only the body, but also all the attachments.
I tried several ways without lucky.
This is my code (please don't look at the missing error checks). Also some part of the code is missing for simplicity.
from email.mime.multipart import MIMEBase, MIMEMultipart
from email import encoders, message, utils, generator , message_from_bytes,message_from_string
def _attachment(filename,file_path=None):
fp_filename = ''
if file_path is not None:
fp_filename = file_path+'/'+filename
else:
fp_filename = self.attachdir+'/'+filename
fd = open(fp_filename, 'rb')
mimetype, mimeencoding = mimetypes.guess_type(filename)
if mimeencoding or (mimetype is None):
mimetype = 'application/octet-stream'
maintype, subtype = mimetype.split('/')
if maintype == 'text':
retval = MIMEText(fd.read(), _subtype=subtype)
else:
retval = MIMEBase(maintype, subtype)
retval.set_payload(fd.read())
encoders.encode_base64(retval)
retval.add_header('Content-Disposition', 'attachment',
filename = filename)
fd.close()
return retval
# ...
# prepare msg body
msg_content = """
<!DOCTYPE html>
<html>
<head>
<title>My Title</title>
<style type="text/css">
span.bold {font-weight: bold;}
table.noborder {border: 0px; padding: 8px;}
th {text-align: left;}
</style>
</head>
<body>
<p>
Hello From Me :-)
</p>
</body>
</html>
"""
#create message obgject
msg = MIMEMultipart('alternative')
msg.attach(MIMEText(msg_content, 'html', 'utf-8'))
msg['From'] = mfrom
msg['To'] = recipient
msg['Reply-to'] = reply
msg['Subject'] = subject
msg['Date'] = utils.formatdate(localtime = 1)
msg.attach(_attachment(filename='samplefile.pdf',file_path='./'))
# no error check reported in this code sample
conn = smtplib.SMTP_SSL(smtpserver,smtpport)
conn.login(smtplogin, smtppass)
conn.sendmail(e.mfrom, [comm.destinatario], msg.as_string())
conn.quit()
with open('file_1.eml', 'w') as f:
gen = generator.Generator(f)
gen.flatten(msg)
msg_b = message_from_string(msg.as_string())
with open('file_2.eml', 'wb') as f:
f.write(bytes(msg_b))
with open('file_3.eml', 'wb') as f:
f.write(msg.as_bytes())
In every file (1,2,3) I can see only the email body: no attachment!
Can you help me?
Solution 1:[1]
Moved from an edit to the question by the OP to an answer.
Use email.message.EmailMessage, as reported in the Python docs.
The old method created some issues in viewing attachments for some users.
This is the working code:
import mimetypes
import smtplib
from email import utils
from email.message import EmailMessage
from email.policy import SMTP
import html2text
# prepare msg body
msg_content = """
<!DOCTYPE html>
<html>
<head>
<title>My Title</title>
<style type="text/css">
span.bold {font-weight: bold;}
table.noborder {border: 0px; padding: 8px;}
th {text-align: left;}
</style>
</head>
<body>
<p>
Hello From Me :-)
</p>
</body>
</html>
"""
mfrom = '[email protected]'
mto = '[email protected]'
file_to_attach = 'testfile.PDF'
subject = 'test attachment'
smtp_server = 'localhost'
# create message object
msg = EmailMessage()
msg['From'] = mfrom
msg['To'] = mto
# msg['Reply-to'] = reply
msg['Subject'] = subject
msg['Date'] = utils.formatdate(localtime = 1)
# generate text version
ht = html2text.HTML2Text()
ht.ignore_links = False
# Add Text Version
msg.set_content(ht.handle(msg_content))
# Add HTML Version
msg.add_alternative(msg_content, subtype='html')
# Manage Attachment
ctype, encoding = mimetypes.guess_type(file_to_attach)
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)
with open(file_to_attach, 'rb') as fp:
# add attachment
msg.add_attachment(fp.read(),
maintype=maintype,
subtype=subtype,
filename=file_to_attach)
# store the message
with open('mail_out.eml', 'wb') as fp:
fp.write(msg.as_bytes(policy=SMTP))
# send the message
with smtplib.SMTP(smtp_server) as s:
# set debug if needed
s.set_debuglevel(1)
# send
s.send_message(msg)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | tripleee |
