Senden von mehrteiligen HTML-E-Mails, die eingebettete Bilder enthalten

73

Ich habe mit dem E-Mail-Modul in Python herumgespielt, möchte aber wissen, wie man Bilder einbettet, die im HTML-Code enthalten sind.

Also zum Beispiel, wenn der Körper so etwas wie ist

<img src="../path/image.png"></img>

Ich möchte image.png in die E-Mail einbetten , und das srcAttribut sollte durch ersetzt werden content-id. Weiß jemand, wie man das macht?

John Jiang
quelle

Antworten:

147

Hier ist ein Beispiel, das ich gefunden habe.

Rezept 473810: Senden Sie eine HTML-E-Mail mit eingebettetem Bild und alternativem Klartext :

HTML ist die Methode der Wahl für diejenigen, die E-Mails mit Rich Text, Layout und Grafiken senden möchten. Oft ist es wünschenswert, die Grafiken in die Nachricht einzubetten, damit die Empfänger die Nachricht ohne weitere Downloads direkt anzeigen können.

Einige Mail-Agenten unterstützen HTML nicht oder ihre Benutzer bevorzugen den Empfang von Nur-Text-Nachrichten. Absender von HTML-Nachrichten sollten als Alternative für diese Benutzer eine Nur-Text-Nachricht enthalten.

Dieses Rezept sendet eine kurze HTML-Nachricht mit einem einzelnen eingebetteten Bild und einer alternativen Nur-Text-Nachricht.

# Send an HTML email with an embedded image and a plain text message for
# email clients that don't want to display the HTML.

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage

# Define these once; use them twice!
strFrom = '[email protected]'
strTo = '[email protected]'

# Create the root message and fill in the from, to, and subject headers
msgRoot = MIMEMultipart('related')
msgRoot['Subject'] = 'test message'
msgRoot['From'] = strFrom
msgRoot['To'] = strTo
msgRoot.preamble = 'This is a multi-part message in MIME format.'

# Encapsulate the plain and HTML versions of the message body in an
# 'alternative' part, so message agents can decide which they want to display.
msgAlternative = MIMEMultipart('alternative')
msgRoot.attach(msgAlternative)

msgText = MIMEText('This is the alternative plain text message.')
msgAlternative.attach(msgText)

# We reference the image in the IMG SRC attribute by the ID we give it below
msgText = MIMEText('<b>Some <i>HTML</i> text</b> and an image.<br><img src="cid:image1"><br>Nifty!', 'html')
msgAlternative.attach(msgText)

# This example assumes the image is in the current directory
fp = open('test.jpg', 'rb')
msgImage = MIMEImage(fp.read())
fp.close()

# Define the image's ID as referenced above
msgImage.add_header('Content-ID', '<image1>')
msgRoot.attach(msgImage)

# Send the email (this example assumes SMTP authentication is required)
import smtplib
smtp = smtplib.SMTP()
smtp.connect('smtp.example.com')
smtp.login('exampleuser', 'examplepass')
smtp.sendmail(strFrom, strTo, msgRoot.as_string())
smtp.quit()
Andrew Hare
quelle
Vielen Dank, ich habe viele Lösungen ausprobiert. Dies ist die, die perfekt funktioniert!
Wukong
@ Andrew Hare: Es gibt zwei mehrteilige Ansichten (die beiden msgText-Instanzen). Ich sehe nicht den jeweils angegebenen Inhaltstyp. Wie würde das empfangende System wissen, welches für das HTML-System gerendert werden soll?
Old Geezer
Ich habe msgText.replace_header ('Content-Type', 'text / html') für die zweite msgText-Instanz hinzugefügt.
Old Geezer
1
FTR: das zweite Argument an den MIMETextKonstruktor ist der Subtyp (Standardeinstellung plain, ist 'html'für die zweite Instanz).
dtk
10
Es funktionierte für mich in Python 3.7.2, aber ich musste Importe anders schreiben: from email.mime.text import MIMEText from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart
Senya
49

Für Python-Versionen 3.4 und höher.

Die akzeptierte Antwort ist ausgezeichnet, aber nur für ältere Python-Versionen (2.x und 3.3) geeignet. Ich denke, es braucht ein Update.

So können Sie dies in neueren Python-Versionen (3.4 und höher) tun:

from email.message import EmailMessage
from email.utils import make_msgid
import mimetypes

msg = EmailMessage()

# generic email headers
msg['Subject'] = 'Hello there'
msg['From'] = 'ABCD <[email protected]>'
msg['To'] = 'PQRS <[email protected]>'

# set the plain text body
msg.set_content('This is a plain text body.')

# now create a Content-ID for the image
image_cid = make_msgid(domain='xyz.com')
# if `domain` argument isn't provided, it will 
# use your computer's name

# set an alternative html body
msg.add_alternative("""\
<html>
    <body>
        <p>This is an HTML body.<br>
           It also has an image.
        </p>
        <img src="cid:{image_cid}">
    </body>
</html>
""".format(image_cid=image_cid[1:-1]), subtype='html')
# image_cid looks like <[email protected]>
# to use it as the img src, we don't need `<` or `>`
# so we use [1:-1] to strip them off


# now open the image and attach it to the email
with open('path/to/image.jpg', 'rb') as img:

    # know the Content-Type of the image
    maintype, subtype = mimetypes.guess_type(img.name)[0].split('/')

    # attach it
    msg.get_payload()[1].add_related(img.read(), 
                                         maintype=maintype, 
                                         subtype=subtype, 
                                         cid=image_cid)


# the message is ready now
# you can write it to a file
# or send it using smtplib
Xyres
quelle
-1

Code funktioniert

    att = MIMEImage(imgData)
    att.add_header('Content-ID', f'<image{i}.{imgType}>')
    att.add_header('X-Attachment-Id', f'image{i}.{imgType}')
    att['Content-Disposition'] = f'inline; filename=image{i}.{imgType}'
    msg.attach(att)
Cleiton Silva
quelle
Hallo! Vielen Dank für die Antwort. Es kann nützlich sein, wenn Sie auch einige Erklärungen zum obigen Code hinzufügen. Auch im OP-Code wird keine imgTypeVariablendefinition angezeigt, sodass Ihr Code eine Ausnahme auslöst.
Charnel