Pythonでメールを送信する

Pythonでメールを送信する

Pythonを使用してメールを送信したいので、おそらくこのチュートリアルを見つけたでしょう。 コードからメール通知を受信したり、アカウントの作成時にユーザーに確認メールを送信したり、組織のメンバーに会費を支払うように通知するメールを送信したい場合があります。 手動でメールを送信するのは時間がかかり、エラーが発生しやすい作業ですが、Pythonで自動化するのは簡単です。

In this tutorial you’ll learn how to

  • SMTP_SSL().starttls()を使用してsecure connectionを設定します

  • Pythonの組み込みsmtplibライブラリを使用して、basic emailsを送信します

  • emailパッケージを使用して、HTML contentおよびattachmentsを含む電子メールを送信します

  • 連絡先データを含むCSVファイルを使用して複数のpersonalized emailsを送信する

  • Yagmailパッケージを使用して、数行のコードのみを使用してGmailアカウントからメールを送信します

このチュートリアルの最後にいくつかのトランザクションメールサービスがあります。これは、大量のメールを送信する場合に役立ちます。

Free Bonus:Click here to get access to a chapter from Python Tricks: The Bookは、Pythonのベストプラクティスと、より美しい+ Pythonicコードをすぐに適用できる簡単な例を示しています。

入門

Pythonには、SMTP(Simple Mail Transfer Protocol)を使用して電子メールを送信するための組み込みのsmtplibモジュールが付属しています。 smtplibは、SMTPにRFC 821プロトコルを使用します。 このチュートリアルの例では、Gmail SMTPサーバーを使用してメールを送信しますが、他のメールサービスにも同じ原則が適用されます。 大多数の電子メールプロバイダーは、このチュートリアルの接続ポートと同じ接続ポートを使用していますが、簡単なGoogle searchを実行して確認することができます。

このチュートリアルを開始するには、送信した電子メールを破棄し、代わりにコマンドプロンプトに出力するset up a Gmail account for developmentまたはset up an SMTP debugging serverを使用します。 両方のオプションを以下に示します。 ローカルSMTPデバッグサーバーは、電子メール機能の問題を修正し、電子メールを送信する前に電子メール機能にバグがないことを確認するのに役立ちます。

オプション1:開発用のGmailアカウントのセットアップ

Gmailアカウントを使用してメールを送信する場合は、コードの開発用に使い捨てアカウントを設定することを強くお勧めします。 これは、Pythonコードからのアクセスを許可するためにGmailアカウントのセキュリティ設定を調整する必要があり、ログイン情報を誤って公開する可能性があるためです。 また、テストアカウントの受信トレイがテストメールで急速にいっぱいになっていることがわかりました。これは、開発用の新しいGmailアカウントをセットアップするのに十分な理由です。

Gmailの優れた機能は、@記号を使用して、@記号の直前にメールアドレスに修飾子を追加できることです。 たとえば、[email protected][email protected]に送信されたメールは両方とも[email protected]に到着します。 メール機能をテストするとき、これを使用して、すべてが同じ受信トレイを指す複数のアドレスをエミュレートできます。

コードをテストするためにGmailアドレスを設定するには、次の手順を実行します。

Gmailアカウントのセキュリティ設定を下げたくない場合は、OAuth2認証フレームワークを使用してPythonスクリプトのアクセス認証情報を取得する方法に関するGoogleのdocumentationを確認してください。

オプション2:ローカルSMTPサーバーのセットアップ

Pythonにプリインストールされているsmtpdモジュールを使用して、ローカルSMTPデバッグサーバーを実行することにより、電子メール機能をテストできます。 指定されたアドレスに電子メールを送信するのではなく、それらを破棄して、コンテンツをコンソールに出力します。 ローカルデバッグサーバーを実行すると、メッセージの暗号化を処理したり、資格情報を使用してメールサーバーにログインしたりする必要がなくなります。

コマンドプロンプトで次のように入力して、ローカルSMTPデバッグサーバーを起動できます。

$ python -m smtpd -c DebuggingServer -n localhost:1025

Linuxでは、sudoを前に付けた同じコマンドを使用します。

このサーバーを介して送信された電子メールはすべて破棄され、各行のbytesオブジェクトとしてターミナルウィンドウに表示されます。

---------- MESSAGE FOLLOWS ----------
b'X-Peer: ::1'
b''
b'From: [email protected]'
b'To: [email protected]'
b'Subject: a local test mail'
b''
b'Hello there, here is a test email'
------------ END MESSAGE ------------

チュートリアルの残りの部分では、Gmailアカウントを使用していると想定しますが、ローカルデバッグサーバーを使用している場合は、SMTPサーバーとしてlocalhostを使用し、ポート1025ではなくポート1025を使用してください。ポート465または587。 これに加えて、login()を使用したり、SSL / TLSを使用して通信を暗号化したりする必要はありません。

プレーンテキストメールの送信

HTMLコンテンツと添付ファイル付きのメールを送信する前に、Pythonを使用してプレーンテキストのメールを送信する方法を学びます。 これらは、簡単なテキストエディターで作成できるメールです。 テキストの書式設定やハイパーリンクのような派手なものはありません。 それについては少し後で学びます。

セキュアSMTP接続の開始

Pythonを介して電子メールを送信するときは、SMTP接続が暗号化されていることを確認する必要があります。これにより、他のユーザーがメッセージとログイン資格情報に簡単にアクセスできなくなります。 SSL(Secure Sockets Layer)とTLS(Transport Layer Security)は、SMTP接続の暗号化に使用できる2つのプロトコルです。 ローカルデバッグサーバーを使用する場合、これらのいずれかを使用する必要はありません。

メールサーバーとの安全な接続を開始するには、2つの方法があります。

  • SMTP_SSL()を使用して最初から保護されているSMTP接続を開始します。

  • .starttls()を使用して暗号化できる、セキュリティで保護されていないSMTP接続を開始します。

どちらの場合でも、GmailはTLSを使用して電子メールを暗号化します。これは、これがSSLのより安全な後継者であるためです。 PythonのSecurity considerationsに従って、sslモジュールのcreate_default_context()を使用することを強くお勧めします。 これにより、システムの信頼できるCA証明書が読み込まれ、ホスト名の確認と証明書の検証が有効になり、合理的に安全なプロトコルと暗号設定を選択しようとします。

Gmailの受信トレイでメールの暗号化を確認する場合は、MoreShow originalに移動して、Receivedヘッダーの下にリストされている暗号化タイプを確認します。

smtplibは、SMTPまたはESMTPリスナーデーモンを備えたインターネットマシンに電子メールを送信するためのPythonの組み込みモジュールです。

最初にSMTP_SSL()を使用する方法を説明します。これは、最初から安全で、.starttls()の代替よりもわずかに簡潔な接続をインスタンス化するためです。 Gmailでは、SMTP_SSL()を使用する場合はポート465に接続し、.starttls()を使用する場合はポート587に接続する必要があることに注意してください。

オプション1:SMTP_SSL()を使用する

以下のコード例は、smtplibSMTP_SSL()を使用してTLS暗号化接続を開始し、GmailのSMTPサーバーとの安全な接続を作成します。 sslのデフォルトのコンテキストは、ホスト名とその証明書を検証し、接続のセキュリティを最適化します。 [email protected]の代わりに自分のメールアドレスを入力してください:

import smtplib, ssl

port = 465  # For SSL
password = input("Type your password and press enter: ")

# Create a secure SSL context
context = ssl.create_default_context()

with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
    server.login("[email protected]", password)
    # TODO: Send email here

with smtplib.SMTP_SSL() as server:を使用すると、インデントされたコードブロックの最後で接続が自動的に閉じられます。 portがゼロの場合、または指定されていない場合、.SMTP_SSL()はSMTP over SSLの標準ポート(ポート465)を使用します。

特に他の人と共有する場合は、コードにメールパスワードを保存することは安全な方法ではありません。 代わりに、上記の例のように、input()を使用して、スクリプトの実行時にユーザーがパスワードを入力できるようにします。 入力時にパスワードを画面に表示したくない場合は、getpassモジュールをインポートし、代わりに.getpass()を使用してパスワードをブラインド入力できます。

オプション2:.starttls()を使用する

.SMTP_SSL()を使用して最初から安全な接続を作成する代わりに、安全でないSMTP接続を作成し、.starttls()を使用して暗号化することができます。

これを行うには、smtplib.SMTPのインスタンスを作成します。これにより、SMTP接続がカプセル化され、そのメソッドにアクセスできるようになります。 簡単に構成するには、スクリプトの最初にSMTPサーバーとポートを定義することをお勧めします。

以下のコードスニペットは、前の例で使用した形式with SMTP() as server:ではなく、構造server = SMTP()を使用しています。 何か問題が発生したときにコードがクラッシュしないようにするには、メインコードをtryブロックに配置し、exceptブロックでエラーメッセージをstdoutに出力します。

import smtplib, ssl

smtp_server = "smtp.gmail.com"
port = 587  # For starttls
sender_email = "[email protected]"
password = input("Type your password and press enter: ")

# Create a secure SSL context
context = ssl.create_default_context()

# Try to log in to server and send email
try:
    server = smtplib.SMTP(smtp_server,port)
    server.ehlo() # Can be omitted
    server.starttls(context=context) # Secure the connection
    server.ehlo() # Can be omitted
    server.login(sender_email, password)
    # TODO: Send email here
except Exception as e:
    # Print any error messages to stdout
    print(e)
finally:
    server.quit()

サーバーに対して自分自身を識別するには、.SMTP()オブジェクトを作成した後、および.starttls()の後に、.helo()(SMTP)または.ehlo()(ESMTP)を呼び出す必要があります。 この関数は、必要に応じて.starttls()および.sendmail()によって暗黙的に呼び出されるため、サーバーのSMTPサービス拡張機能を確認する場合を除いて、.helo()または.ehlo()を使用する必要はありません。 s明示的に。

テキスト形式のメールを送信する

上記のいずれかの方法を使用して安全なSMTP接続を開始した後、.sendmail()を使用して電子メールを送信できます。これは、缶に書かれていることをほぼ実行します。

server.sendmail(sender_email, receiver_email, message)

インポート後、スクリプトの上部でメールアドレスとメッセージコンテンツを定義することをお勧めします。これにより、簡単に変更できます。

sender_email = "[email protected]"
receiver_email = "[email protected]"
message = """\
Subject: Hi there

This message is sent from Python."""

# Send email here

messagestring"Subject: Hi there"で始まり、その後に2つの改行( )が続きます。 これにより、Hi thereが電子メールの件名として表示され、改行に続くテキストがメッセージ本文として扱われます。

以下のコード例は、SMTP_SSL()を使用してプレーンテキストの電子メールを送信します。

import smtplib, ssl

port = 465  # For SSL
smtp_server = "smtp.gmail.com"
sender_email = "[email protected]"  # Enter your address
receiver_email = "[email protected]"  # Enter receiver address
password = input("Type your password and press enter: ")
message = """\
Subject: Hi there

This message is sent from Python."""

context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
    server.login(sender_email, password)
    server.sendmail(sender_email, receiver_email, message)

比較のために、.starttls()で保護されたSMTP接続を介してプレーンテキストの電子メールを送信するコード例を次に示します。 server.ehlo()行は、必要に応じて.starttls()および.sendmail()によって暗黙的に呼び出されるため、省略できます。

import smtplib, ssl

port = 587  # For starttls
smtp_server = "smtp.gmail.com"
sender_email = "[email protected]"
receiver_email = "[email protected]"
password = input("Type your password and press enter:")
message = """\
Subject: Hi there

This message is sent from Python."""

context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
    server.ehlo()  # Can be omitted
    server.starttls(context=context)
    server.ehlo()  # Can be omitted
    server.login(sender_email, password)
    server.sendmail(sender_email, receiver_email, message)

派手なメールを送信する

Pythonの組み込みのemailパッケージを使用すると、より凝ったメールを構造化できます。このメールは、すでに行ったようにsmtplibで転送できます。 以下では、emailパッケージを使用してHTMLコンテンツと添付ファイルを含むメールを送信する方法を学習します。

HTMLコンテンツを含める

電子メールのテキスト(bolditalicsなど)をフォーマットする場合、または画像、ハイパーリンク、またはレスポンシブコンテンツを追加する場合は、HTMLが非常に便利です。 今日の最も一般的な種類のメールは、HTMLとプレーンテキストを組み合わせたMIME(Multipurpose Internet Mail Extensions)マルチパートメールです。 MIMEメッセージは、Pythonのemail.mimeモジュールによって処理されます。 詳細な説明については、the documentationを確認してください。

すべての電子メールクライアントがデフォルトでHTMLコンテンツを表示するわけではなく、セキュリティ上の理由からプレーンテキストの電子メールのみを受信することを選択する人もいるため、HTMLメッセージの代替テキストを含めることが重要です。 電子メールクライアントは最後にマルチパートの添付ファイルを最初に表示するため、プレーンテキストバージョンの後にHTMLメッセージを追加してください。

以下の例では、MIMEText()オブジェクトにメッセージのHTMLバージョンとプレーンテキストバージョンが含まれ、MIMEMultipart("alternative")インスタンスはこれらを2つの代替レンダリングオプションを使用して単一のメッセージに結合します。

import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

sender_email = "[email protected]"
receiver_email = "[email protected]"
password = input("Type your password and press enter:")

message = MIMEMultipart("alternative")
message["Subject"] = "multipart test"
message["From"] = sender_email
message["To"] = receiver_email

# Create the plain-text and HTML version of your message
text = """\
Hi,
How are you?
Real Python has many great tutorials:
www.realpython.com"""
html = """\

  
    

Hi,
How are you?
Real Python has many great tutorials.

""" # Turn these into plain/html MIMEText objects part1 = MIMEText(text, "plain") part2 = MIMEText(html, "html") # Add HTML/plain-text parts to MIMEMultipart message # The email client will try to render the last part first message.attach(part1) message.attach(part2) # Create secure connection with server and send email context = ssl.create_default_context() with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server: server.login(sender_email, password) server.sendmail( sender_email, receiver_email, message.as_string() )

この例では、最初にプレーンテキストとHTMLメッセージを文字列リテラルとして定義し、次にそれらをplain /htmlMIMETextオブジェクトとして格納します。 次に、これらをこの順序でMIMEMultipart("alternative")メッセージに追加し、電子メールサーバーとの安全な接続を介して送信できます。 電子メールクライアントは最後のサブパートを最初にレンダリングしようとするため、プレーンテキストの代替の後にHTMLメッセージを追加することを忘れないでください。

emailパッケージを使用した添付ファイルの追加

テキストデータを処理するように設計された電子メールサーバーにバイナリファイルを送信するには、転送前にエンコードする必要があります。 これは、バイナリデータを印刷可能なASCII文字にエンコードするbase64を使用して最も一般的に行われます。

以下のコード例は、PDFファイルを添付ファイルとして電子メールを送信する方法を示しています。

import email, smtplib, ssl

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

subject = "An email with attachment from Python"
body = "This is an email with attachment sent from Python"
sender_email = "[email protected]"
receiver_email = "[email protected]"
password = input("Type your password and press enter:")

# Create a multipart message and set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Bcc"] = receiver_email  # Recommended for mass emails

# Add body to email
message.attach(MIMEText(body, "plain"))

filename = "document.pdf"  # In same directory as script

# Open PDF file in binary mode
with open(filename, "rb") as attachment:
    # Add file as application/octet-stream
    # Email client can usually download this automatically as attachment
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())

# Encode file in ASCII characters to send by email
encoders.encode_base64(part)

# Add header as key/value pair to attachment part
part.add_header(
    "Content-Disposition",
    f"attachment; filename= {filename}",
)

# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()

# Log in to server using secure context and send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
    server.login(sender_email, password)
    server.sendmail(sender_email, receiver_email, text)

MIMEultipart()メッセージは、RFC5233スタイルのキーと値のペアの形式でパラメーターを受け入れます。これらのパラメーターはディクショナリに格納され、Message基本クラスの.add_header methodに渡されます。

MIMEクラスの使用の詳細については、Pythonのemail.mimeモジュールのdocumentationを確認してください。

複数のパーソナライズされたメールを送信する

組織のメンバーにメールを送信して、寄付金を支払うように通知したいとします。 または、最近の課題の成績を記載したパーソナライズされた電子メールをクラスで生徒に送信することもできます。 これらのタスクはPythonで簡単です。

関連する個人情報を含むCSVファイルを作成する

複数のパーソナライズされた電子メールを送信するための簡単な出発点は、必要なすべての個人情報を含むcreate a CSV (comma-separated values) fileです。 (同意なしに他の人の個人情報を共有しないようにしてください。)CSVファイルは、最初の行に列ヘッダーが含まれていることが多い単純なテーブルと考えることができます。

以下は、Pythonコードと同じフォルダーに保存したファイルcontacts_file.csvの内容です。 架空の人物の名前、住所、成績が含まれています。 [email protected]構造を使用して、すべての電子メールが自分の受信トレイ(この例では[email protected])に確実に届くようにしました。

name,email,grade
Ron Obvious,[email protected],B+
Killer Rabbit of Caerbannog,[email protected],A
Brian Cohen,[email protected],C

CSVファイルを作成するときは、値をコンマで区切り、周囲の空白を入れないでください。

行をループして複数の電子メールを送信する

以下のコード例は、CSVファイルを開き、そのコンテンツの行をループする方法を示しています(ヘッダー行をスキップします)。 すべての連絡先にメールを送信する前にコードが正しく機能することを確認するために、連絡先ごとにSending email to ...を印刷しました。これは、後で実際にメールを送信する機能に置き換えることができます。

import csv

with open("contacts_file.csv") as file:
    reader = csv.reader(file)
    next(reader)  # Skip header row
    for name, email, grade in reader:
        print(f"Sending email to {name}")
        # Send email here

上記の例では、with open(filename) as file:+`makes sure that your file closes at the end of the code block. `+csv.reader()を使用すると、CSVファイルを1行ずつ簡単に読み取り、その値を抽出できます。 next(reader)行はヘッダー行をスキップするため、次の行for name, email, grade in reader:は各コンマで後続の行を分割し、結果の値を文字列nameemail、および%に格納します。 (t5)s現在の連絡先。

CSVファイルの値の片側または両側に空白が含まれている場合は、.strip()メソッドを使用してそれらを削除できます。

パーソナライズされたコンテンツ

str.format()を使用して中括弧のプレースホルダーを入力することにより、パーソナライズされたコンテンツをメッセージに含めることができます。 たとえば、"hi {name}, you {result} your assignment".format(name="John", result="passed")"hi John, you passed your assignment"を提供します。

Python 3.6以降、文字列のフォーマットはf-stringsを使用してよりエレガントに行うことができますが、これらでは、f文字列自体の前にプレースホルダーを定義する必要があります。 スクリプトの先頭で電子メールメッセージを定義し、CSVファイルをループするときに各連絡先のプレースホルダーを入力するために、古い.format()メソッドが使用されます。

これを念頭に置いて、個人に合わせて調整できるプレースホルダーを使用して、一般的なメッセージ本文を設定できます。

コード例

次のコード例では、パーソナライズされた電子メールを複数の連絡先に送信できます。 example aboveのように、連絡先ごとにname,email,gradeを含むCSVファイルをループします。

一般的なメッセージはスクリプトの冒頭で定義されており、CSVファイル内の連絡先ごとに、その{name}{grade}のプレースホルダーが入力され、パーソナライズされた電子メールがとの安全な接続を介して送信されます。前に見たように、Gmailサーバー:

import csv, smtplib, ssl

message = """Subject: Your grade

Hi {name}, your grade is {grade}"""
from_address = "[email protected]"
password = input("Type your password and press enter: ")

context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
    server.login(from_address, password)
    with open("contacts_file.csv") as file:
        reader = csv.reader(file)
        next(reader)  # Skip header row
        for name, email, grade in reader:
            server.sendmail(
                from_address,
                email,
                message.format(name=name,grade=grade),
            )

Yagmail

EnvelopesFlankerYagmailなど、電子メールの送信を容易にするように設計された複数のライブラリがあります。 Yagmailは特にGmailで動作するように設計されており、以下のコード例に示すように、使いやすいAPIを介してメールを送信するプロセスを大幅に簡素化します。

import yagmail

receiver = "[email protected]"
body = "Hello there from Yagmail"
filename = "document.pdf"

yag = yagmail.SMTP("[email protected]")
yag.send(
    to=receiver,
    subject="Yagmail test with attachment",
    contents=body,
    attachments=filename,
)

このコード例は、example using email and smtplibに必要な行の何分の1かでPDFが添付された電子メールを送信します。

Yagmailを設定するときに、the documentationで説明されているように、Gmailの検証をOSのキーリングに追加できます。 これを行わないと、Yagmailは必要に応じてパスワードを入力し、キーリングに自動的に保存するように求めます。

トランザクションメールサービス

大量のメールを送信する予定があり、メールの統計情報を確認し、信頼性の高い配信を確保する場合は、トランザクションメールサービスを検討する価値があります。 次のサービスはすべて、大量のメールを送信するためのプランを支払っていますが、無料のプランも用意されているため、試してみることができます。 これらの無料プランの一部は無期限に有効であり、メールのニーズに十分である可能性があります。

以下は、いくつかの主要なトランザクションメールサービスの無料プランの概要です。 プロバイダー名をクリックすると、そのWebサイトの価格設定セクションに移動します。

プロバイダ 無料プラン

センドグリッド

最初の30日間は40,000通のメール、その後は1日あたり100通

Sendinblue

1日あたり300通のメール

Mailgun

最初の10,000通のメールは無料

Mailjet

1日あたり200通のメール

Amazon SES

62,000通/月

Google searchを実行して、ニーズに最適なプロバイダーを確認するか、無料のプランをいくつか試して、最も使用するAPIを確認することができます。

Sendgridコードの例

Pythonでトランザクションメールサービスを使用する方法のフレーバーを提供するために、Sendgridを使用してメールを送信するためのコード例を次に示します。

import os
import sendgrid
from sendgrid.helpers.mail import Content, Email, Mail

sg = sendgrid.SendGridAPIClient(
    apikey=os.environ.get("SENDGRID_API_KEY")
)
from_email = Email("[email protected]")
to_email = Email("[email protected]")
subject = "A test email from Sendgrid"
content = Content(
    "text/plain", "Here's a test email sent through Python"
)
mail = Mail(from_email, subject, to_email, content)
response = sg.client.mail.send.post(request_body=mail.get())

# The statements below can be included for debugging purposes
print(response.status_code)
print(response.body)
print(response.headers)

このコードを実行するには、最初に以下を行う必要があります。

Sendgrid for MacおよびWindowsの設定方法の詳細については、リポジトリのREADME(Github)を参照してください。

結論

これで、安全なSMTP接続を開始し、連絡先リストのユーザーに複数のパーソナライズされたメールを送信できます!

プレーンテキストの代替手段を使用してHTMLメールを送信し、メールにファイルを添付する方法を学習しました。 Yagmailパッケージは、Gmailアカウントを使用している場合にこれらすべてのタスクを簡素化します。 大量のメールを送信する場合は、トランザクションメールサービスを検討する価値があります。

Pythonでメールを送信することを楽しんでください。覚えておいてください:no spam please