Wie sende ich E-Mail-Anhänge?

282

Ich habe Probleme beim Verstehen, wie ein Anhang mit Python per E-Mail versendet wird. Ich habe erfolgreich einfache Nachrichten mit dem per E-Mail verschickt smtplib. Könnte jemand bitte erklären, wie man einen Anhang in einer E-Mail sendet. Ich weiß, dass andere Beiträge online sind, aber als Python-Anfänger finde ich sie schwer zu verstehen.

Richard
quelle
5
Hier ist eine einfache Implementierung, die mehrere Dateien anhängen und bei einzubettenden Bildern sogar auf diese verweisen kann. datamakessense.com/…
AdrianBR
Ich fand dieses nützliche drupal.org/project/mimemail/issues/911612. Es stellte sich heraus, dass Bildanhänge an einen verwandten untergeordneten Teil angehängt werden müssen. Wenn Sie das Bild an den MIME-Stammteil anhängen, können die Bilder in der Liste der angehängten Elemente angezeigt und in Clients wie Outlook365 in der Vorschau angezeigt werden.
Hinchy
@AdrianBR was ist, wenn ich ein Bild als PDF-Datei habe. PNGs haben Pixelprobleme beim Zoomen, daher sind PNGs nicht gut für mich.
Pinocchio

Antworten:

415

Hier ist ein anderes:

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)
            )
        # After the file is closed
        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()

Es ist fast das gleiche wie im ersten Beispiel ... Aber es sollte einfacher sein, vorbeizuschauen.

Oli
quelle
7
Seien Sie vorsichtig mit veränderlichen Standardeinstellungen
Gringo Suave
11
@ user589983 Warum nicht eine Bearbeitung vorschlagen, wie es jeder andere Benutzer hier tun würde? Ich habe den verbleibenden Verweis in filein geändert f.
Oli
9
Hinweis für Python3-Entwickler: Das Modul "email.Utils" wurde in "email.utils" umbenannt
gecco
6
für python2.5 + ist es einfacher, stattdessen MIMEApplication zu verwenden - reduziert die ersten drei Zeilen der Schleife auf:part = MIMEApplication(open(f, 'rb').read())
mata
5
Der Betreff wurde in der gesendeten E-Mail nicht angezeigt. Funktionierte nur nach dem Ändern der Zeile in msg ['Subject'] = subject. Ich benutze Python 2.7.
Luke
70

Hier ist die modifizierte Version von Olifür 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):
    """Compose and send email with provided info and attachments.

    Args:
        send_from (str): from name
        send_to (list[str]): to name(s)
        subject (str): message title
        message (str): message body
        files (list[str]): list of file paths to be attached to email
        server (str): mail server host name
        port (int): port number
        username (str): server auth username
        password (str): server auth password
        use_tls (bool): use TLS mode
    """
    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()
Ehsan Iran-Nejad
quelle
danke, aber es wäre schön, auch das Grundlegende zu haben: die Syntax für eine einzelne angehängte Datei (unter Verwendung
ihres
Es scheint, dass Sie Ihre Dateien nicht schließen. Es wird Müll gesammelt oder beim Beenden geschlossen, aber es ist eine schlechte Angewohnheit. mit open () als f: ist der richtige Weg.
Comte
Code funktioniert nicht. Falscher Variablenname f im Format (os.path.basename (f)) sollte Format sein (os.path.basename (Pfad))
Chris
1
send_to sollte list [str] sein
Subin
2
Beste Antwort für mich, aber es gibt einen kleinen Fehler: Ersetzen import pathlibdurchfrom pathlib import Path
AleAve81
65

Dies ist der Code, den ich letztendlich verwendet habe:

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


SUBJECT = "Email Data"

msg = MIMEMultipart()
msg['Subject'] = SUBJECT 
msg['From'] = self.EMAIL_FROM
msg['To'] = ', '.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)

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

Code ist ähnlich wie Olis Post. Vielen Dank an alle

Code basierend auf dem Problembeitrag zum E-Mail-Anhang einer Binärdatei .

Richard
quelle
2
Gute Antwort. Wäre schön, wenn es auch Code enthalten würde, der einen Beispieltext hinzufügt.
Steven Bluen
4
Bitte beachten Sie, dass in modernen Versionen der E-Mail-Bibliothek die Modulimporte unterschiedlich sind. zB:from email.mime.base import MIMEBase
Varun Balupuri
27
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import smtplib

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

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

Von hier aus angepasst .

Oli
quelle
Nicht ganz das, wonach ich suche. Die Datei wurde als Text einer E-Mail gesendet. Es fehlen auch Klammern in Zeile 6 und 7. Ich habe das Gefühl, dass wir uns näher kommen
Richard
2
E-Mails sind einfacher Text, und das wird smtplibunterstützt. Um Anhänge zu senden, codieren Sie sie als MIME-Nachricht und senden sie in einer Klartext-E-Mail. Es gibt jedoch ein neues Python-E-Mail-Modul: docs.python.org/library/email.mime.html
Katriel
@katrienlalex ein funktionierendes Beispiel würde einen großen Beitrag zu meinem Verständnis leisten
Richard
1
Sind Sie sicher, dass das obige Beispiel nicht funktioniert? Ich habe keinen SMTP-Server zur Hand, aber ich habe msg.as_string()es mir angesehen und es sieht auf jeden Fall aus wie der Körper einer mehrteiligen MIME-E-Mail. Wikipedia erklärt MIME: en.wikipedia.org/wiki/MIME
Katriel
1
Line 6, in <module> msg.attach(MIMEText(file("text.txt").read())) NameError: name 'file' is not defined
Benjamin2002
7

Ein anderer Weg mit Python 3 (wenn jemand sucht):

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

fromaddr = "sender mail address"
toaddr = "receiver mail address"

msg = MIMEMultipart()

msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "SUBJECT OF THE EMAIL"

body = "TEXT YOU WANT TO SEND"

msg.attach(MIMEText(body, 'plain'))

filename = "fileName"
attachment = open("path of file", "rb")

part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)

msg.attach(part)

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "sender mail password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()

Stellen Sie sicher, dass in Ihrem Google Mail-Konto " weniger sichere Apps " zulässig sind

Sudarshan
quelle
6

Google Mail-Version, die mit Python 3.6 funktioniert (Beachten Sie, dass Sie Ihre Google Mail-Einstellungen ändern müssen, um E-Mails über SMTP von dort aus senden zu können:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from os.path import basename


def send_mail(send_from: str, subject: str, text: str, 
send_to: list, files= None):

    send_to= default_address if not send_to else send_to

    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = ', '.join(send_to)  
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    for f in files or []:
        with open(f, "rb") as fil: 
            ext = f.split('.')[-1:]
            attachedfile = MIMEApplication(fil.read(), _subtype = ext)
            attachedfile.add_header(
                'content-disposition', 'attachment', filename=basename(f) )
        msg.attach(attachedfile)


    smtp = smtplib.SMTP(host="smtp.gmail.com", port= 587) 
    smtp.starttls()
    smtp.login(username,password)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()

Verwendungszweck:

username = '[email protected]'
password = 'top-secret'
default_address = ['[email protected]'] 

send_mail(send_from= username,
subject="test",
text="text",
send_to= None,
files= # pass a list with the full filepaths here...
)

Um es mit einem anderen E-Mail-Anbieter zu verwenden, ändern Sie einfach die SMTP-Konfigurationen.

Ferrarezi
quelle
4

Der einfachste Code, den ich bekommen könnte, ist:

#for attachment email
from django.core.mail import EmailMessage

    def attachment_email(request):
            email = EmailMessage(
            'Hello', #subject
            'Body goes here', #body
            '[email protected]', #from
            ['[email protected]'], #to
            ['[email protected]'], #bcc
            reply_to=['[email protected]'],
            headers={'Message-ID': 'foo'},
            )

            email.attach_file('/my/path/file')
            email.send()

Es basierte auf der offiziellen Django-Dokumentation

Andrade
quelle
3
in deinem Fall musst du django installieren, um eine E-Mail zu senden ... es beantwortet die Frage nicht richtig
comte
@comte 'coz python wird immer nur für Django verwendet, oder?
Auspex
5
@Auspex das ist mein Punkt ;-) Es ist wie die Installation von LibreOffice, um eine Konfigurationsdatei zu bearbeiten ...
Comte
Ich finde das hilfreich und informativ. Es wird nur das eine Modul importiert, und seine Verwendung ist im Vergleich zu den MIME-Reifen, durch die andere springen, recht einfach und elegant. In Ihrem Beispiel ist LibreOffice dagegen schwieriger zu verwenden als der Editor.
Björks Nummer eins Fan
4

Andere Antworten sind ausgezeichnet, obwohl ich immer noch einen anderen Ansatz teilen wollte, falls jemand nach Alternativen sucht.

Der Hauptunterschied besteht darin, dass Sie mit diesem Ansatz HTML / CSS zum Formatieren Ihrer Nachricht verwenden können, um kreativ zu werden und Ihrer E-Mail etwas Stil zu verleihen. Obwohl Sie nicht gezwungen sind, HTML zu verwenden, können Sie auch nur einfachen Text verwenden.

Beachten Sie, dass diese Funktion das Senden der E-Mail an mehrere Empfänger akzeptiert und auch das Anhängen mehrerer Dateien ermöglicht.

Ich habe dies nur auf Python 2 versucht, aber ich denke, es sollte auch auf 3 gut funktionieren:

import os.path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

def send_email(subject, message, from_email, to_email=[], attachment=[]):
    """
    :param subject: email subject
    :param message: Body content of the email (string), can be HTML/CSS or plain text
    :param from_email: Email address from where the email is sent
    :param to_email: List of email recipients, example: ["[email protected]", "[email protected]"]
    :param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
    """
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['From'] = from_email
    msg['To'] = ", ".join(to_email)
    msg.attach(MIMEText(message, 'html'))

    for f in attachment:
        with open(f, 'rb') as a_file:
            basename = os.path.basename(f)
            part = MIMEApplication(a_file.read(), Name=basename)

        part['Content-Disposition'] = 'attachment; filename="%s"' % basename
        msg.attach(part)

    email = smtplib.SMTP('your-smtp-host-name.com')
    email.sendmail(from_email, to_email, msg.as_string())

Ich hoffe das hilft! :-)

Antony Fuentes Artavia
quelle
2
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import mimetypes
import email.mime.application

smtp_ssl_host = 'smtp.gmail.com'  # smtp.mail.yahoo.com
smtp_ssl_port = 465
s = smtplib.SMTP_SSL(smtp_ssl_host, smtp_ssl_port)
s.login(email_user, email_pass)


msg = MIMEMultipart()
msg['Subject'] = 'I have a picture'
msg['From'] = email_user
msg['To'] = email_user

txt = MIMEText('I just bought a new camera.')
msg.attach(txt)

filename = 'introduction-to-algorithms-3rd-edition-sep-2010.pdf' #path to file
fo=open(filename,'rb')
attach = email.mime.application.MIMEApplication(fo.read(),_subtype="pdf")
fo.close()
attach.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attach)
s.send_message(msg)
s.quit()

Zur Erklärung können Sie diesen Link verwenden, der ordnungsgemäß erklärt wird: https://medium.com/@sdoshi579/to-send-an-email-along-with-attachment-using-smtp-7852e77623

sdoshi
quelle
2
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import smtplib

msg = MIMEMultipart()

password = "password"
msg['From'] = "from_address"
msg['To'] = "to_address"
msg['Subject'] = "Attached Photo"
msg.attach(MIMEImage(file("abc.jpg").read()))
file = "file path"
fp = open(file, 'rb')
img = MIMEImage(fp.read())
fp.close()
msg.attach(img)
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
server.login(msg['From'], password)
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()
Abdul Haseeb
quelle
2
Hallo, Willkommen, Bitte posten Sie immer eine Erklärung Ihrer Antwort, wenn Sie eine Frage zum besseren Verständnis beantworten
Ali
0

Unten finden Sie eine Kombination aus dem, was ich aus dem Beitrag von SoccerPlayer hier und dem folgenden Link gefunden habe, der mir das Anhängen einer XLSX-Datei erleichtert hat. Hier gefunden

file = 'File.xlsx'
username=''
password=''
send_from = ''
send_to = 'recipient1 , recipient2'
Cc = 'recipient'
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = send_to
msg['Cc'] = Cc
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = ''
server = smtplib.SMTP('smtp.gmail.com')
port = '587'
fp = open(file, 'rb')
part = MIMEBase('application','vnd.ms-excel')
part.set_payload(fp.read())
fp.close()
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename='Name File Here')
msg.attach(part)
smtp = smtplib.SMTP('smtp.gmail.com')
smtp.ehlo()
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to.split(',') + msg['Cc'].split(','), msg.as_string())
smtp.quit()
TonyRyan
quelle
0

Mit meinem Code können Sie E-Mail-Anhänge mit Google Mail senden, die Sie benötigen:

Stellen Sie Ihre Google Mail-Adresse auf " IHRE SMTP- E-MAIL HIER " ein.

Legen Sie Ihr Passwort für das Google Mail-Konto auf " IHR SMTP-PASSWORT HIER_ " fest.

Im Teil ___EMAIL TO RECEIVE THE MESSAGE_ müssen Sie die Ziel-E-Mail-Adresse festlegen.

Alarmbenachrichtigung ist das Thema,

Jemand hat den Raum betreten, Bild beigefügt ist der Körper

["/home/pi/webcam.jpg"] ist ein Bildanhang .

#!/usr/bin/env python
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import os

USERNAME = "___YOUR SMTP EMAIL HERE___"
PASSWORD = "__YOUR SMTP PASSWORD HERE___"

def sendMail(to, subject, text, files=[]):
    assert type(to)==list
    assert type(files)==list

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

    msg.attach( MIMEText(text) )

    for file in files:
        part = MIMEBase('application', "octet-stream")
        part.set_payload( open(file,"rb").read() )
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"'
                       % os.path.basename(file))
        msg.attach(part)

    server = smtplib.SMTP('smtp.gmail.com:587')
    server.ehlo_or_helo_if_needed()
    server.starttls()
    server.ehlo_or_helo_if_needed()
    server.login(USERNAME,PASSWORD)
    server.sendmail(USERNAME, to, msg.as_string())
    server.quit()

sendMail( ["___EMAIL TO RECEIVE THE MESSAGE__"],
        "Alarm notification",
        "Someone has entered the room, picture attached",
        ["/home/pi/webcam.jpg"] )
John Rua
quelle
Lange nicht gesehen! Gut zu sehen, dass Sie Ihren Code richtig zuordnen und direkt in die Antwort aufnehmen. Es ist jedoch im Allgemeinen verpönt, denselben Antwortcode bei mehreren Fragen zu kopieren und einzufügen. Wenn sie wirklich mit derselben Lösung gelöst werden können, sollten Sie die Fragen stattdessen als Duplikate kennzeichnen.
Das_Geek
0

Sie können auch den gewünschten Anhangstyp in Ihrer E-Mail angeben. Als Beispiel habe ich pdf verwendet:

def send_email_pdf_figs(path_to_pdf, subject, message, destination, password_path=None):
    ## credits: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script
    from socket import gethostname
    #import email
    from email.mime.application import MIMEApplication
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    import smtplib
    import json

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.starttls()
    with open(password_path) as f:
        config = json.load(f)
        server.login('[email protected]', config['password'])
        # Craft message (obj)
        msg = MIMEMultipart()

        message = f'{message}\nSend from Hostname: {gethostname()}'
        msg['Subject'] = subject
        msg['From'] = '[email protected]'
        msg['To'] = destination
        # Insert the text to the msg going by e-mail
        msg.attach(MIMEText(message, "plain"))
        # Attach the pdf to the msg going by e-mail
        with open(path_to_pdf, "rb") as f:
            #attach = email.mime.application.MIMEApplication(f.read(),_subtype="pdf")
            attach = MIMEApplication(f.read(),_subtype="pdf")
        attach.add_header('Content-Disposition','attachment',filename=str(path_to_pdf))
        msg.attach(attach)
        # send msg
        server.send_message(msg)

Inspirationen / Credits an: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script

Pinocchio
quelle