Send e-mail to Gmail with inline image using Python

后端 未结 2 1435
故里飘歌
故里飘歌 2020-12-01 07:11

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 hr

相关标签:
2条回答
  • 2020-12-01 07:31

    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
    
    0 讨论(0)
  • 2020-12-01 07:46

    I think you need to add the following lines:

    from email.mime.image import MIMEImage
    
    body = MIMEText('<p>Test Image<img src="cid:testimage" /></p>', _subtype='html')
    msg.attach(body)
    
    
    img = MIMEImage(image.read(), 'jpeg')
    img.add_header('Content-Id', '<testimage>')
    msg.attach(img)
    

    testimage should be replaced with a unique identifier

    0 讨论(0)
提交回复
热议问题