使用 Python 将带有内嵌图像的电子邮件发送到 Gmail

本文介绍了使用 Python 将带有内嵌图像的电子邮件发送到 Gmail的处理方法,对大家解决问题具有一定的参考价值

问题描述

我的目标是使用 Python 向具有内嵌图像的 Gmail 用户发送电子邮件.由于图像的敏感性(来自我的工作数据),无法在线托管此图像然后通过 href 链接到它.

我尝试将 base64 版本编码为 HTML 然后发送的是 HTML,但众所周知这是行不通的.然后我注意到在 Gmail 中,您可以将图像拖放到发送框中,它会在接收端内嵌显示.鉴于此,我然后尝试从 Python 发送一封电子邮件,并将图像作为附件.这在下面的代码中可以看到,但不幸的是图像没有内联显示.

我的问题是:如何发送图像以使其内嵌显示?

导入smtplib从 email.MIMEMultipart 导入 MIMEMultipart从 email.MIMEBase 导入 MIMEBase从 email.MIMEText 导入 MIMEText从电子邮件导入编码器导入操作系统gmail_user = "user1@gmail.com"gmail_pwd = "通过"to = "user2@gmail.com"主题 = "报告"text = "图片报告"附加 = 'TESTING.png'msg = MIMEMultipart()msg['发件人'] = gmail_usermsg['到'] = 到msg['主题'] = 主题msg.attach(MIMEText(text))part = MIMEBase('application', 'octet-stream')part.set_payload(open(attach, 'rb').read())Encoders.encode_base64(部分)part.add_header('内容配置','依恋;文件名="%s"' % os.path.basename(attach))msg.attach(部分)邮件服务器 = smtplib.SMTP("smtp.gmail.com", 587)邮件服务器.elo()邮件服务器.starttls()邮件服务器.elo()mailServer.login(gmail_user, gmail_pwd)mailServer.sendmail(gmail_user, to, msg.as_string())# 应该是mailServer.quit(),但是崩溃了...邮件服务器.close()

当我手动将内嵌图片发送给自己时,原始电子邮件"是这样的:

 内容类型:多部分/相关;边界=047d7bd761fe73e03304e7e02237--047d7bd761fe73e03304e7e02237内容类型:多部分/替代;边界=047d7bd761fe73e03004e7e02236--047d7bd761fe73e03004e7e02236内容类型:文本/纯文本;字符集=ISO-8859-1[图像:内嵌图像 1]--047d7bd761fe73e03004e7e02236内容类型:文本/html;字符集=ISO-8859-1<div dir="ltr"><img alt="内嵌图像 1" src="cid:ii_141810ee4ae92ac6" height="400" width="534"><br></div>--047d7bd761fe73e03004e7e02236----047d7bd761fe73e03304e7e02237内容类型:图像/png;名称="测试.png"内容传输编码:base64内容 ID:<ii_141810ee4ae92ac6>X 附件 ID:ii_141810ee4ae92ac6

当我通过 Python 将它作为附件发送给自己时,情况就大不相同了:

内容类型:多部分/混合;边界="================6881579935569047077=="MIME 版本:1.0(....这里删除了一些东西)--================6881579935569047077==内容类型:文本/纯文本;字符集=us-ascii"MIME 版本:1.0内容传输编码:7 位报告见附件.--================6881579935569047077==内容类型:应用程序/八位字节流MIME 版本:1.0内容传输编码:base64Content-Disposition:附件;文件名=TESTING.png"

解决方案

看来遵循 gmail 电子邮件模板是可行的:

* multipart/alternative- 文字/普通- 多部分/相关+ 文本/html<img src="cid:msgid"/>+ 图像/png内容 ID:

基于 email 模块文档:

#!/usr/bin/env python3导入html导入 mimetypesfrom email.headerregistry 导入地址从 email.message 导入 EmailMessage从 email.utils 导入 make_msgid从 pathlib 导入路径title = '图片报告...'path = Path('TESTING.png')me = Address("Pepé Le Pew", *gmail_user.rsplit('@', 1))msg = 电子邮件消息()msg['主题'] = '报告...'msg['来自'] = 我msg['To'] = [我]msg.set_content('[image: {title}]'.format(title=title)) # 文本/纯文本cid = make_msgid()[1:-1] # strip <>msg.add_alternative(#文本/html'<img src="cid:{cid}" alt="{alt}"/>'.format(cid=cid, alt=html.escape(title, quote=True)),子类型='html')maintype, subtype = mimetypes.guess_type(str(path))[0].split('/', 1)msg.get_payload()[1].add_related(#image/pngpath.read_bytes(), maintype, subtype, cid="<{cid}>".format(cid=cid))# 将消息的本地副本保存到磁盘路径('outgoing.msg').write_bytes(bytes(msg))

通过 gmail 发送 msg:

导入smtplib导入 ssl使用 smtplib.SMTP('smtp.gmail.com', timeout=10) 作为 s:s.starttls(context=ssl.create_default_context())s.login(gmail_user, gmail_password)s.send_message(msg)

Python 2/3 兼容版本

* multipart/related- 多部分/替代+ 文字/普通+ 文本/html<div dir="ltr"><img src="cid:ii_xyz" alt="..."><br></div>- 图像/jpeg内容 ID:<ii_xyz>

基于 发送带有嵌入图像和纯文本替代的 HTML 电子邮件:

#!/usr/bin/env python# -*- 编码:utf-8 -*-导入 cgi导入 uuid导入操作系统从 email.mime.multipart 导入 MIMEMultipart从 email.mime.text 导入 MIMEText从 email.mime.image 导入 MIMEImagefrom email.header 导入标题img = dict(title=u'图片报告...', path=u'TESTING.png', cid=str(uuid.uuid4()))msg = MIMEMultipart('相关')msg['Subject'] = Header(u'Report…', 'utf-8')msg['发件人'] = gmail_usermsg['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'
''<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)使用 open(img['path'], 'rb') 作为文件: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:

导入ssls = 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.pemca_certs='cacert.pem'))s.set_debuglevel(0)尝试:s.login(gmail_user, gmail_pwd)s.sendmail(msg['From'], [to], msg.as_string())最后:退出()

SMTP_SSL 是可选的,您可以改用问题中的 starttls 方法:

导入smtplib进口插座导入 ssl导入系统类 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', None)self.ssl_kwargs['certfile'] = kwargs.pop('certfile', None)smtplib.SMTP_SSL.__init__(self, host, port, **kwargs)def _get_socket(self, host, port, timeout):如果 self.debuglevel >0:打印>>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)返回 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 a HTML then sending th is HTML, 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 email module docs:

#!/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 use starttls 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,WP2

WordPress使用python会话上载文件

我需要上传图像到wordpress编程,理想情况下没有安装额外的插件。不过,我对涉及插件的最佳实践持开放态度。到目前为止,我已经能够使用会话登录和移动站点,但是当我尝试将文件上载到媒体时-新建.php或异步-上传.php我收到以下错误消息The file is a test text file with a single line (also the upload limit on the site is 1GB) so it\"s not the common file size limit. This ...

日期:2021-08-21 05:00:01 浏览:785

压缩序列化的Python数据最节省空间的方法是什么?

本文介绍了压缩序列化的Python数据最节省空间的方法是什么?的处理方法,对大家解决问题具有一定的参考价值 问题描述 发件人the Python documentation:默认情况下,Pickle数据格式使用相对紧凑的二进制表示。如果您需要最佳大小特性,您可以高效地压缩酸洗数据。我将在一个运行了几个小时的过程结束时序列化...

日期:2022-06-23 08:50:34 浏览:755

在Python中,有没有一种方法可以将一个单词分割成等分?

本文介绍了在Python中,有没有一种方法可以将一个单词分割成等分?的处理方法,对大家解决问题具有一定的参考价值 问题描述 几周前我问了这个问题,得到了答案this is the original post但我需要将输出分成相等的部分,无论字符串的长度如何,所以在我发布的第一个帖子中,我得到了这个答案,它很好地工作了,这要...

日期:2022-06-24 06:52:06 浏览:476

如何在 Google AppEngine Python37 中获取凭据

本文介绍了如何在 Google AppEngine Python37 中获取凭据的处理方法,对大家解决问题具有一定的参考价值 问题描述 我在 AppEngine Python3.7 标准中启动了新应用.I started new app in AppEngine Python3.7 stadard.我正在尝试使用以下代码段...

日期:2022-06-24 09:00:27 浏览:549

为什么 python 字符串和元组是不可变的?

本文介绍了为什么 python 字符串和元组是不可变的?的处理方法,对大家解决问题具有一定的参考价值 问题描述 我不确定为什么字符串和元组是不可变的;使它们不可变的优点和缺点是什么?I am not sure why strings and tuples were made to be immutable; what ar...

日期:2022-06-24 09:00:30 浏览:886

使用 Python 解析 Gmail 并将所有早于日期的内容标记为“已读"

本文介绍了使用 Python 解析 Gmail 并将所有早于日期的内容标记为“已读"的处理方法,对大家解决问题具有一定的参考价值 问题描述 长话短说,我创建了一个新的 gmail 帐户,并将其他几个帐户关联到该帐户(每个帐户都有 1000 条消息),我正在导入这些帐户.所有导入的邮件都以未读的形式到达,但我需要它们显示为已...

日期:2022-06-24 10:00:29 浏览:809

了解python线程错误

本文介绍了了解python线程错误的处理方法,对大家解决问题具有一定的参考价值 问题描述 阅读http://bugs.python.org/msg160297,我可以看到Stephen White编写的一个简单脚本,它演示了该异常是如何导致python线程出错的Exception AttributeError: Attri...

日期:2022-06-24 21:00:28 浏览:946

从python调用url时获取“错误"的页面源

本文介绍了从python调用url时获取“错误"的页面源的处理方法,对大家解决问题具有一定的参考价值 问题描述 尝试从网站检索页面源时,得到的文本与通过 Web 浏览器查看相同页面源时完全不同(且更短).Trying to retrieve the page source from a website, I get a c...

日期:2022-06-25 01:00:31 浏览:600

基于 Python 类的装饰器,带有可以装饰方法或函数的参数

本文介绍了基于 Python 类的装饰器,带有可以装饰方法或函数的参数的处理方法,对大家解决问题具有一定的参考价值 问题描述 我见过很多 Python 装饰器的例子:I've seen many examples of Python decorators that are:函数样式装饰器(包装函数)类样式装饰器(实现 __...

日期:2022-06-25 04:00:31 浏览:929

用python解析outlook .msg文件

本文介绍了用python解析outlook .msg文件的处理方法,对大家解决问题具有一定的参考价值 问题描述 环顾四周,没有找到满意的答案.有谁知道如何使用 Python 解析 Outlook 中的 .msg 文件?Looked around and couldn't find a satisfactory answer...

日期:2022-06-25 06:00:30 浏览:641