106 votes

Envoi de courriels html multipartites contenant des images incorporées

J'ai joué avec le module de messagerie en python, mais je voudrais savoir comment intégrer les images qui sont incluses dans le code html.

Ainsi, par exemple, si le corps est quelque chose comme

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

Je voudrais intégrer image.png dans l'email, et le src doit être remplacé par content-id . Quelqu'un sait-il comment faire ?

192voto

Andrew Hare Points 159332

Voici un exemple que j'ai trouvé.

Recette 473810 : Envoyer un courriel HTML avec une image intégrée et un texte alternatif en clair. :

Le HTML est la méthode de choix pour ceux qui qui souhaitent envoyer des courriels avec du texte riche, une mise en page et des graphiques. Il est souvent souhaitable d'intégrer les graphiques dans le le message afin que les destinataires puissent afficher le message directement, sans avoir à téléchargements.

Certains agents de messagerie ne supportent pas le HTML ou leurs utilisateurs préfèrent recevoir des messages texte brut. Les expéditeurs de messages HTML doivent inclure un message en texte brut comme alternative pour ces utilisateurs utilisateurs.

Cette recette envoie un court message HTML avec une seule image incorporée et un autre message en texte brut.

# 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 = 'from@example.com'
strTo = 'to@example.com'

# 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()

0 votes

Merci beaucoup, j'ai essayé de nombreuses solutions, c'est celle qui fonctionne parfaitement !

0 votes

@Andrew Hare : Il y a deux vues multipartites (les deux instances msgText). Je ne vois pas le type de contenu spécifié pour chacune. Comment le système récepteur pourrait-il savoir lequel rendre pour la vue Html ?

0 votes

J'ai ajouté msgText.replace_header('Content-Type', 'text/html') pour la deuxième instance de msgText.

96voto

xyres Points 552

Pour les versions Python 3.4 et supérieures.

La réponse acceptée est excellente, mais ne convient qu'aux anciennes versions de Python (2.x et 3.3). Je pense qu'elle a besoin d'une mise à jour.

Voici comment vous pouvez le faire dans les versions plus récentes de Python (3.4 et plus) :

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 <abcd@xyz.com>'
msg['To'] = 'PQRS <pqrs@xyz.com>'

# 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 <long.random.number@xyz.com>
# 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

8voto

miksus Points 71

J'ai réalisé à quel point certaines choses sont pénibles avec le SMTP et les bibliothèques de courrier électronique et j'ai pensé que je devais faire quelque chose avec ça. J'ai fait une bibliothèque qui facilite l'intégration d'images dans le code HTML :

from redmail import EmailSender
email = EmailSender(host="<SMTP HOST>", port=0)

email.send(
    sender="me@example.com",
    receivers=["you@example.com"]
    subject="An email with image",
    html="""
        <h1>Look at this:</h1>
        {{ my_image }}
    """, 
    body_images={
        "my_image": "path/to/image.png"
    }
)

Désolé pour la promotion mais je pense que c'est assez génial. Vous pouvez fournir l'image comme Matplotlib Figure , Oreiller Image ou tout aussi bytes si votre image est dans ces formats. Il utilise Jinja pour la création de modèles.

Si vous devez contrôler la taille de l'image, vous pouvez également le faire :

email.send(
    sender="me@example.com",
    receivers=["you@example.com"]
    subject="An email with image",
    html="""
        <h1>Look at this:</h1>
        <img src="{{ my_image.src }}" width=200 height=300>
    """, 
    body_images={
        "my_image": "path/to/image.png"
    }
)

Vous pouvez simplement l'installer avec pip :

pip install redmail

C'est (espérons-le) tout ce dont vous avez besoin pour l'envoi d'e-mails (il en a beaucoup plus) et il est bien testé. J'ai également écrit une documentation complète : https://red-mail.readthedocs.io/en/latest/ et le code source est trouvé aquí .

0voto

Merci pour la réponse.

J'ai trouvé un site intéressant, si vous aimez aussi vérifier cette http://theticktalk.wordpress.com/2013/06/29/how-to-email-mrtg-graphs-using-python-smtp-library-gmail/

-5voto

Cleiton Silva Points 17

Le code fonctionne

    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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X