web-dev-qa-db-fra.com

Comment envoyer des pièces jointes à l'aide de SMTP?

Je souhaite écrire un programme qui envoie un courrier électronique à l'aide de Python SMTPLIB . J'ai cherché dans le document et les RFCS, mais je n'ai rien trouvé lié aux pièces jointes. Ainsi, je suis sûr qu'il y a un concept de niveau supérieur qui me manque. Quelqu'un peut-il s'impliquer sur la façon dont les pièces jointes fonctionnent dans SMTP?

21
Jason Baker

Ce que vous voulez vérifier est le module email. Il vous permet de construire [~ # ~] mime [~ # ~ ~] - des messages conformes que vous envoyez ensuite avec SmTplib.

11
Jürgen A. Erhard

Voici un exemple de message avec une pièce jointe PDF, un "corps" de texte et envoyé via gmail.

# Import smtplib for the actual sending function
import smtplib

# For guessing MIME type
import mimetypes

# Import the email modules we'll need
import email
import email.mime.application

# Create a text/plain message
msg = email.mime.Multipart.MIMEMultipart()
msg['Subject'] = 'Greetings'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'

# The main body is just another attachment
body = email.mime.Text.MIMEText("""Hello, how are you? I am fine.
This is a rather Nice letter, don't you think?""")
msg.attach(body)

# PDF attachment
filename='simple-table.pdf'
fp=open(filename,'rb')
att = email.mime.application.MIMEApplication(fp.read(),_subtype="pdf")
fp.close()
att.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(att)

# send via Gmail server
# NOTE: my ISP, Centurylink, seems to be automatically rewriting
# port 25 packets to be port 587 and it is trashing port 587 packets.
# So, I use the default port 25, but I authenticate. 
s = smtplib.SMTP('smtp.gmail.com')
s.starttls()
s.login('[email protected]','xyzpassword')
s.sendmail('[email protected]',['[email protected]'], msg.as_string())
s.quit()
29
Kevin Buchs

Voici un exemple que j'ai lancé hors d'une demande de travail que nous avons faite. Il crée un courrier électronique HTML avec une pièce jointe Excel.

  import smtplib,email,email.encoders,email.mime.text,email.mime.base

  smtpserver = 'localhost'
  to = ['[email protected]']
  fromAddr = '[email protected]'
  subject = "my subject"

  # create html email
  html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
  html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">'
  html +='<body style="font-size:12px;font-family:Verdana"><p>...</p>'
  html += "</body></html>"
  emailMsg = email.MIMEMultipart.MIMEMultipart('alternative')
  emailMsg['Subject'] = subject
  emailMsg['From'] = fromAddr
  emailMsg['To'] = ', '.join(to)
  emailMsg['Cc'] = ", ".join(cc)
  emailMsg.attach(email.mime.text.MIMEText(html,'html'))

  # now attach the file
  fileMsg = email.mime.base.MIMEBase('application','vnd.ms-Excel')
  fileMsg.set_payload(file('exelFile.xls').read())
  email.encoders.encode_base64(fileMsg)
  fileMsg.add_header('Content-Disposition','attachment;filename=anExcelFile.xls')
  emailMsg.attach(fileMsg)

  # send email
  server = smtplib.SMTP(smtpserver)
  server.sendmail(fromAddr,to,emailMsg.as_string())
  server.quit()
19
Mark

Eh bien, les pièces jointes ne sont pas traitées de manière particulière, elles sont "juste" des feuilles de l'arborescence d'objets de message. Vous pouvez trouver les réponses à toutes les questions concernant des mésasges conformes à MIME dans this section de la documentation sur le email python package.

En général, tout type d'attachement (lecture: données binaires brutes) peut être représenté en utilisant la base64 (ou similaire) Content-Transfer-Encoding.

3
shylent

Voici comment envoyer des courriers électroniques avec des pièces jointes de fichier zip et de la matière codée UTF-8 + corps.

Il n'était pas simple de comprendre celui-ci, en raison du manque de documentation et d'échantillons pour ce cas particulier.

Les caractères non-ASCII dans ReplyTo doivent être codés avec, par exemple, ISO-8859-1. Il existe probablement une fonction qui peut faire cela.

Conseil:
[.____] Envoyez-vous un e-mail, enregistrez-le et examinez le contenu pour déterminer comment faire la même chose à Python.

Voici le code, pour Python 3:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:set ts=4 sw=4 et:

from os.path import basename
from smtplib import SMTP
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import parseaddr, formataddr
from base64 import encodebytes

def send_email(recipients=["[email protected]"],
         subject="Test subject æøå",
         body="Test body æøå",
         zipfiles=[],
         server="smtp.somewhere.xyz",
         username="bob",
         password="password123",
         sender="Bob <[email protected]>",
         replyto="=?ISO-8859-1?Q?M=F8=F8=F8?= <[email protected]>"): #: bool
    """Sends an e-mail"""
    to = ",".join(recipients)
    charset = "utf-8"
    # Testing if body can be encoded with the charset
    try:
        body.encode(charset)
    except UnicodeEncodeError:
        print("Could not encode " + body + " as " + charset + ".")
        return False

    # Split real name (which is optional) and email address parts
    sender_name, sender_addr = parseaddr(sender)
    replyto_name, replyto_addr = parseaddr(replyto)

    sender_name = str(Header(sender_name, charset))
    replyto_name = str(Header(replyto_name, charset))

    # Create the message ('plain' stands for Content-Type: text/plain)
    try:
        msgtext = MIMEText(body.encode(charset), 'plain', charset)
    except TypeError:
        print("MIMEText fail")
        return False

    msg = MIMEMultipart()

    msg['From'] = formataddr((sender_name, sender_addr))
    msg['To'] = to #formataddr((recipient_name, recipient_addr))
    msg['Reply-to'] = formataddr((replyto_name, replyto_addr))
    msg['Subject'] = Header(subject, charset)

    msg.attach(msgtext)

    for zipfile in zipfiles:
        part = MIMEBase('application', "Zip")
        b = open(zipfile, "rb").read()
        # Convert from bytes to a base64-encoded ascii string
        bs = encodebytes(b).decode()
        # Add the ascii-string to the payload
        part.set_payload(bs)
        # Tell the e-mail client that we're using base 64
        part.add_header('Content-Transfer-Encoding', 'base64')
        part.add_header('Content-Disposition', 'attachment; filename="%s"' %
                        os.path.basename(zipfile))
        msg.attach(part)

    s = SMTP()
    try:
        s.connect(server)
    except:
        print("Could not connect to smtp server: " + server)
        return False

    if username:
        s.login(username, password)
    print("Sending the e-mail")
    s.sendmail(sender, recipients, msg.as_string())
    s.quit()
    return True

def main():
    send_email()

if __name__ == "__main__":
    main()
3
Alexander