343 votes

Comment envoyer des pièces jointes par e-mail ?

Je rencontre des problèmes pour comprendre comment envoyer une pièce jointe par e-mail en utilisant Python. J'ai réussi à envoyer des messages simples avec le smtplib. Est-ce que quelqu'un pourrait s'il vous plaît m'expliquer comment envoyer une pièce jointe par e-mail. Je sais qu'il y a d'autres publications en ligne, mais en tant que débutant en Python je les trouve difficiles à comprendre.

6 votes

Voici une mise en œuvre simple qui peut attacher plusieurs fichiers, et même les mentionner dans le cas des images à intégrer. datamakessense.com/…

0 votes

J'ai trouvé cela utile drupal.org/project/mimemail/issues/911612, il s'avère que les pièces jointes d'images doivent être attachées à une partie enfant de type lié. Si vous attachez l'image à la partie MIME racine, les images peuvent apparaître dans la liste des éléments attachés et être prévisualisées dans des clients comme Outlook365.

0 votes

@AdrianBR Et si j'ai une image au format PDF. Les fichiers PNG ont des problèmes de pixels lors du zoom, donc les PNG ne me conviennent pas.

504voto

Oli Points 65050

Voici un autre:

import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate

def send_mail(send_from, send_to, subject, text, files=None,
              server="127.0.0.1"):
    assert isinstance(send_to, list)

    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    for f in files or []:
        with open(f, "rb") as fil:
            part = MIMEApplication(
                fil.read(),
                Name=basename(f)
            )
        # Après la fermeture du fichier
        part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
        msg.attach(part)

    smtp = smtplib.SMTP(server)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()

C'est à peu près la même chose que le premier exemple... Mais il devrait être plus facile à mettre en place.

9 votes

Faites attention aux valeurs par défaut mutables: stackoverflow.com/questions/101268/hidden-features-of-python‌​/…

1 votes

-1 La boucle for ne fonctionnera pas. Doit être remplacée par 'for file in files'.

11 votes

@user589983 Pourquoi ne pas suggérer une modification comme le ferait tout autre utilisateur ici ? J'ai modifié la référence restante à file en f.

104voto

pcboy Points 61

Voici la version modifiée d'Oli pour python 3

import smtplib
from pathlib import Path
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders

def send_mail(send_from, send_to, subject, message, files=[],
              server="localhost", port=587, username='', password='',
              use_tls=True):
    """Composer et envoyer un email avec les informations fournies et les pièces jointes.

    Args:
        send_from (str): nom de l'expéditeur
        send_to (list[str]): nom(s) du/des destinataire(s)
        subject (str): titre du message
        message (str): corps du message
        files (list[str]): liste des chemins des fichiers à attacher à l'email
        server (str): nom d'hôte du serveur de messagerie
        port (int): numéro de port
        username (str): nom d'utilisateur d'authentification du serveur
        password (str): mot de passe d'authentification du serveur
        use_tls (bool): utiliser le mode TLS
    """
    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach(MIMEText(message))

    for path in files:
        part = MIMEBase('application', "octet-stream")
        with open(path, 'rb') as file:
            part.set_payload(file.read())
        encoders.encode_base64(part)
        part.add_header('Content-Disposition',
                        'attachment; filename={}'.format(Path(path).name))
        msg.attach(part)

    smtp = smtplib.SMTP(server, port)
    if use_tls:
        smtp.starttls()
    smtp.login(username, password)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.quit()

0 votes

Merci mais ce serait bien aussi d'avoir les bases: la syntaxe pour un seul fichier joint (en utilisant son chemin)

0 votes

Il semble que vous ne fermiez pas vos fichiers, ils seront collectés par le ramasse-miettes ou fermés à la sortie mais ce n'est pas une bonne habitude. avec open() comme f: c'est la bonne façon.

0 votes

Le code ne fonctionne pas. Le nom de variable incorrect "f" dans format(os.path.basename(f)) devrait être format(os.path.basename(chemin))

74voto

Richard Points 1905

Ceci est le code que j'ai fini par utiliser :

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders

SUBJECT = "Données par email"

msg = MIMEMultipart()
msg['Sujet'] = SUJET
msg['De'] = self.EMAIL_FROM
msg['À'] = ', '.join(self.EMAIL_TO)

part = MIMEBase('application', "octet-stream")
part.set_payload(open("text.txt", "rb").read())
Encoders.encode_base64(part)

part.add_header('Content-Disposition', 'attachment; filename="text.txt"')

msg.attach(part)

serveur = smtplib.SMTP(self.EMAIL_SERVER)
serveur.sendmail(self.EMAIL_FROM, self.EMAIL_TO, msg.as_string())

Le code est très similaire à celui du post d'Oli.

Code basé sur le post de Problème de pièce jointe de fichier binaire par email.

3 votes

Bonne réponse. Ce serait bien si cela contenait également du code ajoutant un exemple de texte corporel.

8 votes

Veuillez noter que, dans les versions récentes de la bibliothèque e-mail - les importations de modules sont différentes. Par exemple : from email.mime.base import MIMEBase

0 votes

Utilisation de python3.10 avec Windows, j'ai cette erreur AttributeError: 'MIMEMultipart' object has no attribute 'encode'

29voto

Oli Points 65050
de l'email.MIMEMultipart importer MIMEMultipart
de l'email.MIMEText importer MIMEText
de l'email.MIMEImage importer MIMEImage
import smtplib

msg = MIMEMultipart()
msg.attach(MIMEText(file("text.txt").read()))
msg.attach(MIMEImage(file("image.png").read()))

# pour envoyer
mailer = smtplib.SMTP()
mailer.connect()
mailer.sendmail(from_, to, msg.as_string())
mailer.close()

Adapté de ici.

0 votes

Pas tout à fait ce que je recherche. Le fichier a été envoyé en tant que corps d'un email. Il manque également des crochets sur les lignes 6 et 7. J'ai l'impression que nous nous rapprochons cependant

2 votes

Les emails sont en texte brut, et c'est ce que smtplib supporte. Pour envoyer des pièces jointes, vous les encodez sous forme de message MIME et les envoyez dans un email en texte brut. Il existe cependant un nouveau module python pour les emails : docs.python.org/library/email.mime.html

0 votes

@katrienlalex un exemple concret serait très utile pour m'aider à comprendre

4voto

RelicScoth Points 644

Quelques années de retard sur celui-ci, mais assurez-vous d'avoir quelque chose dans la partie corps de votre message, car certains clients interpréteront une pièce jointe comme le corps s'il est par ailleurs vide.

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