使用Python向内联图像发送电子邮件到Gmail [英] Send e-mail to Gmail with inline image using Python
问题描述
我的目标是使用Python向具有内联图像的Gmail用户发送电子邮件。由于图像的敏感性(我的工作数据),因此不可能在线托管此图像,然后通过 href
链接到该图像。
我尝试将 base64
版本编码为 HTML
然后发送th是 HTML
,但这是众所周知的不起作用。然后我注意到,在Gmail中,您可以将图像拖放到发送框中,并在接收端显示内联。鉴于此,我尝试以Python的形式发送电子邮件作为附件。这在下面的代码中看到,但不幸的是,图像不会内联显示。
我的问题是:如何发送图像,使其显示为内联?
$ b $从电子邮件中导入smtplib
从电子邮件导入smtplib
从email.MIMEBase导入MIMEMultipart
MIMEBase导入MIMEBase
来自email.MIMEText import MIMEText
从电子邮件导入编码器
import os
gmail_user =user1@gmail.com
gmail_pwd =pass
to =user2 @ gmail。 com
subject =Report
text =图片报告
attach ='TESTING.png'
msg = MIMEMultipart()
msg ['From'] = gmail_user
msg ['To'] = to
msg ['Subject'] = subject
msg.attach(MIMEText )
part = MIMEBase('application','octet-stream')
part.set_payload(open(attach,'rb')。read())
编码器.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename =%s'%os.path.basename(attach))
msg.attach (部分)
mailServer = smtplib.SMTP(smtp.gmail.com,587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user ,gmail_pwd)
mailServer.sendmail(gmail_user,to,msg.as_string())
#应该是mailServer.quit(),但是崩溃...
mailServer.close()
当我手动将内置图像发送给自己时,这是原始电子邮件的样子: p>
内容类型:multipart / related; boundary = 047d7bd761fe73e03304e7e02237
--047d7bd761fe73e03304e7e02237
内容类型:multipart / alternative; boundary = 047d7bd761fe73e03004e7e02236
--047d7bd761fe73e03004e7e02236
内容类型:text / plain; charset = ISO-8859-1
[image:Inline images 1]
--047d7bd761fe73e03004e7e02236
内容类型:text / html; charset = ISO-8859-1
< div dir =ltr>< img alt =Inline images 1src =cid:ii_141810ee4ae92ac6height =400width = 534\" ><峰; br>< / DIV>
--047d7bd761fe73e03004e7e02236--
--047d7bd761fe73e03304e7e02237
内容类型:image / png; name =Testing.png
内容传输编码:base64
Content-ID:< ii_141810ee4ae92ac6>
X-Attachment-Id:ii_141810ee4ae92ac6
当我通过Python发送给自己时,附件是非常不同的:
内容类型:multipart / mixed; border ================ 6881579935569047077 ==
MIME版本:1.0
(....某些东西被删除)
- - =============== 6881579935569047077 ==
内容类型:text / plain; charset =us-ascii
MIME版本:1.0
Content-Transfer-Encoding:7bit
请参阅附件。
- =============== 6881579935569047077 ==
内容类型:应用程序/八位字节流
MIME版本:1.0
Content-Transfer-Encoding:base64
Content-Disposition:attachment;文件名=TESTING.png
gmail电子邮件模板工作原理:
* multipart / alternative
- text / plain
- multipart / related
+ text / html
< img src =cid:msgid/>
+ image / png
Content-ID:< msgid>
根据 电子邮件
模块文档:
#!/ usr / bin / env python3
import html
import mimetypes
from email.headerregistry import地址
from email.message import EmailMessage
from email.utils import make_msgid
from pathlib import Path
title ='图片报告...'
path = Path('TESTING。 png')
me = Address(PepéLe Pew,* gmail_user.rsplit('@',1))
msg = EmailMessage()
msg ['Subject '] ='Report ...'
msg ['From'] =我
msg ['To'] = [我]
msg.set_content('[image:{title}]' .format(title = title))#text / plain
cid = make_msgid()[1:-1]#strip<>
msg.add_alternative(#text / html
'< img src =cid:{cid}alt ={alt}/>'
.format(cid = cid ,alt = html.escape(title,quote = True)),
subtype ='html')
maintype,subtype = mimetypes.guess_type(str(path))[0] .split(' ',1)
msg.get_payload()[1] .add_related(#image / png
path.read_bytes(),maintype,subtype,cid =< {cid}>格式(cid = cid))
#保存到磁盘本地副本的消息
路径('outgoing.msg')。write_bytes(bytes(msg))
通过gmail发送 msg
import smtplib
import ssl
with smtplib.SMTP('smtp.gmail.com',timeout = 10)as s:
s.starttls(context = ssl.create_default_context())
s.login(gmail_user,gmail_password)
s.send_message(msg)
Python 2/3兼容版本
multipart / related
- multipart / alternative
+ text / pl ain
+ text / html
< div dir =ltr>< img src =cid:ii_xyzalt =...>< br>< / div> ;
- image / jpeg
Content-ID:< ii_xyz>
根据:
#!/ usr / bin / env python
# - * - 编码:utf-8 - * -
import cgi
import uuid
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.header import Header
img = dict(title = u'Picture report ...',path = u'TESTING.png',cid = str(uuid.uuid4()))
msg = MIMEMultipart('related')
msg ['Subject'] = Header(u'Report ...','utf-8')
msg ['From'] = gmail_user
msg ['To'] =,.join([to])
msg_alternative = MIMEMultipart('alternative')
msg.attach(msg_alternative)
msg_text = MIMEText(u'[image:{title}]'。format(** img), 'plain','utf-8')
msg_alternative.attach(msg_text)
msg_html = MIMEText(u'< div dir =ltr>'
' < img src =cid:{cid}alt ={alt}>< br>< / div>'
.format(alt = cgi.escape(img ['title'] ,$ = $)
$ c $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
with open(img ['path '],'rb')as file:
msg_image = MIMEImage(file.read(),name = os.path.basename(img ['path']))
msg.attach(msg_image)
msg_image.add_header('Content-ID','< {}>'。format(img ['cid']))
通过gmail发送 msg
import ssl
/ pre>
s = SMTP_SSL('smtp.gmail.com',timeout = 10,
ssl_kwargs = dict(cert_reqs = ssl.CERT_REQUIRED,
ssl_version = ssl.PROTOCOL_TLSv1,
#http://curl.haxx.s
s.set_debuglevel(0)
try:
s.login(gmail_user,gmail_pwd)
s.sendmail(msg ['From'],[to],msg.as_string())
finally:
s.quit()
SMTP_SSL
是可选的,您可以使用starttls
方法从您的问题:import smtplib
import socket
import ssl
import sys
class SMTP_SSL(smtplib.SMTP_SSL):
添加对其他ssl选项的支持。
def __init __(self,host,port = 0,* * kwargs)
self.ssl_kwargs = kwargs.pop('ssl_kwargs',{})
self.ssl_kwargs ['keyfile'] = kwargs.pop('keyfile',无)
self.ssl_kwargs ['certfile'] = kwargs.pop('certfile',None)
smtplib.SMTP_SSL .__ init __(self,host,port,** kwargs)
def _get_socket(自我,主机,端口,超时):
如果自己.debuglevel> 0:
print>> sys.stderr,'connect:',(host,port)
new_socket = socket.create_connection((host,port),timeout)
new_socket = ssl。 wrap_socket(new_socket,** self.ssl_kwargs)
self.file = getattr(smtplib,'SSLFakeFile',lambda x:None)(new_socket)
return new_socket
My objective is to use Python to send an e-mail to a Gmail user that has an inline image. It is not possible to host this image online and then link to it through a
href
, due to the sensitive nature of the images (data from my work).I've tried encoding the
base64
version into aHTML
then sending th isHTML
, but this is well known to not work. I then noticed that in Gmail you can drag and drop an image into the send box and it will show up inline in the receiving end. Given this I then tried to send an e-mail from Python with the image as an attachment. This is seen in the below code, but unfortunately the image doesn't show up inline.My question is then: How to send the image such that it shows up inline?
import smtplib from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email.MIMEText import MIMEText from email import Encoders import os gmail_user = "user1@gmail.com" gmail_pwd = "pass" to = "user2@gmail.com" subject = "Report" text = "Picture report" attach = 'TESTING.png' msg = MIMEMultipart() msg['From'] = gmail_user msg['To'] = to msg['Subject'] = subject msg.attach(MIMEText(text)) part = MIMEBase('application', 'octet-stream') part.set_payload(open(attach, 'rb').read()) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attach)) msg.attach(part) mailServer = smtplib.SMTP("smtp.gmail.com", 587) mailServer.ehlo() mailServer.starttls() mailServer.ehlo() mailServer.login(gmail_user, gmail_pwd) mailServer.sendmail(gmail_user, to, msg.as_string()) # Should be mailServer.quit(), but that crashes... mailServer.close()
When I send the inline image to myself manually this is what the "original email" looks like:
Content-Type: multipart/related; boundary=047d7bd761fe73e03304e7e02237 --047d7bd761fe73e03304e7e02237 Content-Type: multipart/alternative; boundary=047d7bd761fe73e03004e7e02236 --047d7bd761fe73e03004e7e02236 Content-Type: text/plain; charset=ISO-8859-1 [image: Inline images 1] --047d7bd761fe73e03004e7e02236 Content-Type: text/html; charset=ISO-8859-1 <div dir="ltr"><img alt="Inline images 1" src="cid:ii_141810ee4ae92ac6" height="400" width="534"><br></div> --047d7bd761fe73e03004e7e02236-- --047d7bd761fe73e03304e7e02237 Content-Type: image/png; name="Testing.png" Content-Transfer-Encoding: base64 Content-ID: <ii_141810ee4ae92ac6> X-Attachment-Id: ii_141810ee4ae92ac6
When I send it to myself through Python as an attachment it is very different:
Content-Type: multipart/mixed; boundary="===============6881579935569047077==" MIME-Version: 1.0 (.... some stuff deleted here) --===============6881579935569047077== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit See attachment for report. --===============6881579935569047077== Content-Type: application/octet-stream MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="TESTING.png"
解决方案It seems that following the gmail email template works:
* multipart/alternative - text/plain - multipart/related + text/html <img src="cid:msgid"/> + image/png Content-ID: <msgid>
Based on the example from
#!/usr/bin/env python3 import html import mimetypes from email.headerregistry import Address from email.message import EmailMessage from email.utils import make_msgid from pathlib import Path title = 'Picture report…' path = Path('TESTING.png') me = Address("Pepé Le Pew", *gmail_user.rsplit('@', 1)) msg = EmailMessage() msg['Subject'] = 'Report…' msg['From'] = me msg['To'] = [me] msg.set_content('[image: {title}]'.format(title=title)) # text/plain cid = make_msgid()[1:-1] # strip <> msg.add_alternative( # text/html '<img src="cid:{cid}" alt="{alt}"/>' .format(cid=cid, alt=html.escape(title, quote=True)), subtype='html') maintype, subtype = mimetypes.guess_type(str(path))[0].split('/', 1) msg.get_payload()[1].add_related( # image/png path.read_bytes(), maintype, subtype, cid="<{cid}>".format(cid=cid)) # save to disk a local copy of the message Path('outgoing.msg').write_bytes(bytes(msg))
To send
msg
via gmail:import smtplib import ssl with smtplib.SMTP('smtp.gmail.com', timeout=10) as s: s.starttls(context=ssl.create_default_context()) s.login(gmail_user, gmail_password) s.send_message(msg)
Python 2/3 compatible version
* multipart/related - multipart/alternative + text/plain + text/html <div dir="ltr"><img src="cid:ii_xyz" alt="..."><br></div> - image/jpeg Content-ID: <ii_xyz>
Based on Send an HTML email with embedded image and plain text alternate:
#!/usr/bin/env python # -*- coding: utf-8 -*- import cgi import uuid import os from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage from email.header import Header img = dict(title=u'Picture report…', path=u'TESTING.png', cid=str(uuid.uuid4())) msg = MIMEMultipart('related') msg['Subject'] = Header(u'Report…', 'utf-8') msg['From'] = gmail_user msg['To'] = ", ".join([to]) msg_alternative = MIMEMultipart('alternative') msg.attach(msg_alternative) msg_text = MIMEText(u'[image: {title}]'.format(**img), 'plain', 'utf-8') msg_alternative.attach(msg_text) msg_html = MIMEText(u'<div dir="ltr">' '<img src="cid:{cid}" alt="{alt}"><br></div>' .format(alt=cgi.escape(img['title'], quote=True), **img), 'html', 'utf-8') msg_alternative.attach(msg_html) with open(img['path'], 'rb') as file: msg_image = MIMEImage(file.read(), name=os.path.basename(img['path'])) msg.attach(msg_image) msg_image.add_header('Content-ID', '<{}>'.format(img['cid']))
To send
msg
via gmail:import ssl s = SMTP_SSL('smtp.gmail.com', timeout=10, ssl_kwargs=dict(cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1, # http://curl.haxx.se/ca/cacert.pem ca_certs='cacert.pem')) s.set_debuglevel(0) try: s.login(gmail_user, gmail_pwd) s.sendmail(msg['From'], [to], msg.as_string()) finally: s.quit()
SMTP_SSL
is optional, you could usestarttls
method from your question instead:import smtplib import socket import ssl import sys class SMTP_SSL(smtplib.SMTP_SSL): """Add support for additional ssl options.""" def __init__(self, host, port=0, **kwargs): self.ssl_kwargs = kwargs.pop('ssl_kwargs', {}) self.ssl_kwargs['keyfile'] = kwargs.pop('keyfile', None) self.ssl_kwargs['certfile'] = kwargs.pop('certfile', None) smtplib.SMTP_SSL.__init__(self, host, port, **kwargs) def _get_socket(self, host, port, timeout): if self.debuglevel > 0: print>>sys.stderr, 'connect:', (host, port) new_socket = socket.create_connection((host, port), timeout) new_socket = ssl.wrap_socket(new_socket, **self.ssl_kwargs) self.file = getattr(smtplib, 'SSLFakeFile', lambda x: None)(new_socket) return new_socket
这篇关于使用Python向内联图像发送电子邮件到Gmail的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!