368 Stimmen

Wie sende ich E-Mail-Anhänge?

Ich habe Probleme, zu verstehen, wie man eine Anlage mit Python per E-Mail versendet. Ich habe erfolgreich einfache Nachrichten mit dem smtplib verschickt. Könnte mir bitte jemand erklären, wie man eine Anlage in einer E-Mail versendet. Ich weiß, dass es andere Beiträge online gibt, aber als Python-Anfänger fällt es mir schwer, sie zu verstehen.

6 Stimmen

Hier ist eine einfache Implementierung, die mehrere Dateien anhängen kann und sogar in Bezug auf Bilder eingebettet werden kann. datamakessense.com/…

0 Stimmen

Ich fand das nützlich drupal.org/project/mimemail/issues/911612 stellt sich heraus, dass Bilddateianhänge an einen damit verbundenen Typ-Kindteil angehängt werden müssen. Wenn Sie das Bild an den Wurzel-MIME-Teil anhängen, können die Bilder in der Liste der angehängten Elemente angezeigt und in Clienten wie Outlook365 vorab angezeigt werden.

536voto

Oli Punkte 226885

Hier ist ein weiteres:

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)
            )
        # Nachdem die Datei geschlossen ist 
        part['Content-Disposition'] = 'Anhang; Dateiname="%s"' % basename(f)
        msg.attach(part)

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

Es ist im Wesentlichen das gleiche wie das erste Beispiel ... Aber es sollte einfacher einzufügen sein.

10 Stimmen

1 Stimmen

-1 Die for-Schleife wird nicht funktionieren. Sollte 'for file in files' lesen.

11 Stimmen

@user589983 Warum schlagen Sie nicht eine Bearbeitung vor, wie es jeder andere Benutzer hier tun würde? Ich habe die verbleibende Referenz zu file in f geändert.

116voto

Ehsan Iran-Nejad Punkte 1557

Hier ist die modifizierte Version von Oli fü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):
    """Zusammensetzen und Senden von E-Mails mit bereitgestellten Informationen und Anhängen.

    Args:
        send_from (str): Absendername
        send_to (list[str]): Empfängername(n)
        subject (str): Betreff
        message (str): Nachrichtentext
        files (list[str]): Liste der Dateipfade, die an die E-Mail angehängt werden sollen
        server (str): Name des E-Mail-Servers
        port (int): Portnummer
        username (str): Benutzername für Serverauthentifizierung
        password (str): Passwort für Serverauthentifizierung
        use_tls (bool): TLS verwenden
    """
    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 Stimmen

Danke, aber es wäre schön, auch das Grundlegende zu haben: die Syntax für eine einzelne angehängte Datei (unter Verwendung ihres Pfades)

0 Stimmen

Es scheint, dass du deine Dateien nicht schließt. Sie werden zwar wahrscheinlich vom Garbage Collector bereinigt oder beim Beenden geschlossen, aber das ist eine schlechte Angewohnheit. Mit open() als f: ist der richtige Weg.

0 Stimmen

Der Code funktioniert nicht. Der falsche Variablenname f in format(os.path.basename(f)) sollte format(os.path.basename(path)) sein.

76voto

Richard Punkte 14088

Dies ist der Code, den ich schließlich verwendet habe:

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

SUBJECT = "E-Mail-Daten"

msg = MIMEMultipart()
msg['Betreff'] = SUBJECT 
msg['Von'] = self.EMAIL_FROM
msg['An'] = ', '.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())

Der Code ist größtenteils der gleiche wie in Oli's Beitrag.

Code basiert auf Problemlösung für binäre Dateianhänge in E-Mails.

3 Stimmen

Gute Antwort. Es wäre schön, wenn es auch Code enthielte, der einen Beispielsatz hinzufügt.

9 Stimmen

Bitte beachten Sie, dass in modernen Versionen der E-Mail-Bibliothek die Modulimporte anders sind. z.B.: from email.mime.base import MIMEBase

0 Stimmen

Verwenden von Python3.10 mit Windows, ich habe diesen Fehler AttributeError: 'MIMEMultipart'-Objekt hat kein Attribut 'encode'

29voto

Oli Punkte 226885
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()))

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

Angepasst von hier.

0 Stimmen

Nicht ganz das, was ich suche. Die Datei wurde als E-Mail-Body gesendet. Es fehlen auch Klammern in Zeile 6 und 7. Ich habe das Gefühl, wir kommen jedoch näher.

2 Stimmen

E-Mails sind reiner Text, und das ist das, was smtplib unterstützt. Um Anhänge zu versenden, codieren Sie sie als MIME-Nachricht und senden Sie sie in einer E-Mail im Klartext. Es gibt jedoch ein neues Python-E-Mail-Modul: docs.python.org/library/email.mime.html

0 Stimmen

@katrienlalex Ein Arbeitsbeispiel würde mir sehr helfen, um mein Verständnis zu verbessern

16voto

tripleee Punkte 155951

Weil es hier viele Antworten für Python 3 gibt, aber keine, die zeigen, wie die überarbeitete email-Bibliothek ab Python 3.6 verwendet wird, hier eine schnelle Kopie aus der aktuellen email Beispiele-Dokumentation. (Ich habe es etwas abgekürzt, um Schnörkel wie das Raten des korrekten MIME-Typs zu entfernen.)

Moderner Code, der auf Python >3.5 abzielt, sollte nicht mehr die email.message.Message API verwenden (einschließlich der verschiedenen Klassen MIMEText, MIMEMultipart, MIMEBase usw.) oder das noch ältere mimetypes-Gedöns.

from email.message import EmailMessage
import smtplib
from pathlib import Path

msg = EmailMessage()
msg["Subject"] = "Unser Familientreffen"
msg["From"] = "ich "
msg["To"] = "empfänger "
# auf keinen Fall das .preamble verändern

msg.set_content("Hallo, Opfer! Schau dir diese Bilder an")

picpath = Path("Pfad/zum/Anhang.png")
with picpath.open("rb") as fp:
    msg.add_attachment(
        fp.read(),
        maintype="image", subtype="png",
        filename=picpath.name)

# Beachten Sie, wie smtplib jetzt eine send_message() Methode enthält
with smtplib.SMTP("localhost") as s:
    s.send_message(msg)

Die moderne email.message.EmailMessage API ist jetzt deutlich vielseitiger und logischer als die ältere Version der Bibliothek. Es gibt immer noch einige Probleme bei der Darstellung in der Dokumentation (zum Beispiel ist es nicht offensichtlich, wie man den Content-Disposition: eines Anhangs ändert; und die Diskussion des policy-Moduls ist wahrscheinlich zu obskur für die meisten Neulinge) und im Grunde genommen müssen Sie immer noch eine Idee davon haben, wie die MIME-Struktur aussehen soll (obwohl die Bibliothek sich jetzt endlich um vieles kümmert, was zuvor sehr mühsam war). Vielleicht schauen Sie sich Was sind die "Parts" in einer multipart Email? für eine kurze Einführung an.

Die Verwendung von localhost als Ihrem SMTP-Server funktioniert offensichtlich nur, wenn tatsächlich ein SMTP-Server auf Ihrem lokalen Computer läuft. Das ordnungsgemäße Versenden von E-Mails von Ihrem System ist eine ziemlich komplexe separate Frage. Für einfache Anforderungen verwenden Sie wahrscheinlich Ihr vorhandenes E-Mail-Konto und den E-Mail-Server Ihres Anbieters (suchen Sie nach Beispielen für die Verwendung von Port 587 mit Google, Yahoo oder was auch immer Sie haben – was genau funktioniert, hängt in gewisser Weise vom Anbieter ab; einige werden nur Port 465 oder den veralteten Port 25 unterstützen, der jedoch jetzt im Wesentlichen auf öffentlich zugänglichen Servern aufgrund der Spam-Filterung unmöglich ist).

0 Stimmen

Ich finde die Idee großartig, einfach das email.message.EmailMessage-API zu verwenden. Könnten Sie ein Codebeispiel für die Funktion bereitstellen, die mehrere Anhänge mit verschiedenen Untertypen hat?

2 Stimmen

Die verlinkte Dokumentation enthält mehrere Beispiele. Aber kurz gesagt, for anhang, haupt, unter in (("pfad/zum/bild.png", "bild", "png"), ("ein/weiteres/verzeichnis/rache.pdf", "anwendung", "pdf"), ("irgendwo/anders/abgrund.xlsx", "anwendung", "octet-stream")): with open(anhang, "rb") as fp: msg.add_attachment(fp.read(), maintype=haupt, subtype=unter) (zu faul, um den richtigen MIME-Typ für XLSX nachzuschlagen; Freunde lassen Freunde sowieso kein Excel verwenden).

0 Stimmen

Ich schlage vor, es auch zu bearbeiten, um filename=... hinzuzufügen, d. h. with open("path/to/attachment.png", "rb") as fp: msg.add_attachment( fp.read(), maintype="image", subtype="png", filename="attachment.png"), damit der Anhang mit einem korrekten Namen heruntergeladen wird und richtig angezeigt wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X