Email-Versand mit Python

Manchmal möchte man eine Email aus einem Python-Skript heraus versenden, dazu gibt es in Python zwei Möglichkeiten.
Laut offizieller Dokumentation ist die Variante mit email.mime die Legacy API. Dies bedeutet, es ist die ältere Variante, und sie könnte in naher Zukunft möglicherweise auf deprecated gesetzt werden. Die zweite Variante ist neu, und verwendet die email.message API.

Zum Vergleich, und da vermutlich aktuell noch sehr viel Code die ältere Variante enthält, werden hier beide Möglichkeiten betrachtet.

Die folgenden Methoden können jeweils als Template dienen. Der Code ist den eignen Bedürfnissen entsprechend abzuändern oder zu ergänzen. Im Beispiel wird auch eine Datei eingelesen, und als Anhang mitgesendet.

Im Hauptprogramm werden zunächst die benötigten Daten für den Emailversand ermittelt und ggf. aufbereitet. Diese Daten werden entweder eingegeben oder aus einer Datei gelesen (z.B. .env). Liegen alle Daten vor, werden die Methoden mit den jeweiligen Parametern hintereinander aufgerufen.
Dem Mailserver kann auch eine Liste von Strings für die Empfänger übergeben werden, hier im Beispiel wird nur eine Adresse verwendet.
Außerdem können auch CC_Empfänger angegeben werden.

Variante mit email.mime (Legacy API)

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

def _send_email(email_sender: str, email_address: str, email_content_as_string: str):
  mailserver = smtplib.SMTP(<servername>)
  mailserver.login(<user>, <password>) # hängt vom Systemumfeld ab, ggf. ist Login nicht notwendig
  mailserver.sendmail(email_sender, email_address, email_content_as_string)
  mailserver.quit()

def _create_email(email_sender: str, email_recipient: str, email_subject: str, email_text: str,
                byte_attachment: pathlib.Path, filename: str) -> MIMEMultipart:
  email_content = MIMEMultipart()
  email_content['From'] = email_sender
  email_content['Subject'] = email_subject
  email_content['To'] = email_recipient
  email_content.attach(MIMEText(email_text))

    if byte_attachment:
      document = MIMEBase('application', 'octet-stream')

      with open(byte_attachment, 'rb') as file:
          document.set_payload(file.read())

        encoders.encode_base64(document)
      document.add_header('Content-Disposition', f'attachment; filename="{byte_attachment.name}"')
      email_content.attach(document)

    return email_content


if __name__ == "__main__":

    # Daten für die Parameter ermitteln, entweder eingeben lassen oder aus Datei einlesen

  email_full_content = _create_email(email_from, email_to, subject, email_message, datafile_path)
    _send_email(email_from, email_to, email_full_content.as_string())

Variante mit email.message

import smtplib
from email.message import EmailMessage

def _send_email(email_content: EmailMessage, email_server: str):
    mailserver = smtplib.SMTP(email_server)
    mailserver.send_message(email_content)
    mailserver.quit()

def _create_email(email_sender: str, email_recipient: str, email_subject: str, email_text: str,
                  byte_attachment: pathlib.Path) -> EmailMessage:

    email_content = EmailMessage()
    email_content['From'] = email_sender
    email_content['To'] = email_recipient
    email_content['Subject'] = email_subject
    email_content.set_content(email_text)

    if byte_attachment:
        attachment_type, encoding = mimetypes.guess_type(byte_attachment)

        if attachment_type is None or encoding is not None:
            attachment_type = 'application/octet-stream'

        maintype, subtype = attachment_type.split('/', 1)

        with open(byte_attachment, 'rb') as file:
            email_content.add_attachment(file.read(),
                                         maintype=maintype,
                                         subtype=subtype,
                                         filename=byte_attachment.name)

    return email_content


if __name__ == "__main__":
    # Daten für die Parameter ermitteln, entweder eingeben lassen oder aus Datei einlesen

    email_full_content = _create_email(email_from, email_to, subject, email_message, datafile_path)
    _send_email(email_full_content, smtp_server)