# 20.12. `smtplib` --- SMTP プロトコルクライアント

ソースコード: Lib/smtplib.py

`smtplib` モジュールは、SMTPまたはESMTPのリスナーデーモンを備えた任意のインターネット上のホストにメールを送るために使用することができる SMTPクライアント・セッション・オブジェクトを定義します。 SMTPおよびESMTPオペレーションの詳細は、 RFC 821 (Simple Mail Transfer Protocol) や RFC 1869 (SMTP Service Extensions)を調べてください。

class `smtplib.``SMTP`([host[, port[, local_hostname[, timeout]]]])

  `SMTP` インスタンスはSMTPコネクションをカプセル化し、 SMTPとESMTPの命令をサポートをします。オプションであるhostとportを与えた場合は、 SMTPクラスのインスタンスが作成されると同時に、 `connect()` メソッドを呼び出し初期化されます。`connect()` 呼び出しが成功コード以外を返した場合、 `SMTPConnectError` 例外が送出されます。local_hostname を指定する場合、これは HELO/EHLO コマンドでのローカルホストの FQDN として使われます。指定しない場合はローカルホスト名は `socket.getfqdn()` が使われます。オプションの timeout 引数を与える場合、コネクションの接続時などのブロックする操作におけるタイムアウト時間を秒数で設定します。(指定されなかった場合は、グローバルのデフォルトタイムアウト設定が利用されます)。タイムアウトに達すると `socket.timeout` 例外が送出されます。

  For normal use, you should only require the initialization/connect, `sendmail()`, and `SMTP.quit()` methods. An example is included below.

  バージョン 2.6 で変更: timeout が追加されました

class `smtplib.``SMTP_SSL`([host[, port[, local_hostname[, keyfile[, certfile[, timeout]]]]]])

  `SMTP_SSL` のインスタンスは `SMTP` のインスタンスと全く同じように動作します。 `SMTP_SSL` は、接続の最初の段階からSSLが要求され、 `starttls()` では対応できない場合にのみ利用されるべきです。 host が指定されなかった場合は、localhostが利用されます。 port が指定されなかった場合は、標準の SMTP-over-SSL ポート(465) が利用されます。 local_hostname は `SMTP` クラスのものと同じです。 keyfile と certfile もオプションで、SSL接続のための、PEMフォーマットのプライベートキーと、証明パス (certificate chain) ファイルを指定することができます。オプションの timeout 引数を与える場合、コネクションの接続時などのブロックする操作におけるタイムアウト時間を秒数で設定します (指定されなかった場合は、グローバルのデフォルトタイムアウト設定が利用されます)。タイムアウトに達すると `socket.timeout` 例外が送出されます。

  バージョン 2.6 で追加.

class `smtplib.``LMTP`([host[, port[, local_hostname]]])

  ESMTPに非常に似ているLMTPプロトコルは、SMTPクライアントに基づいています。 LMTPにはよくUnixソケットが利用されるので、 `connect()` メソッドは通常の host:port サーバーと同じようにUnixソケットもサポートしています。local_hostname は `SMTP` クラスのものと同じです。 Unixソケットを指定するには、 host 引数に、 '/' で始まる絶対パスを指定します。

  認証は、通常のSMTP機構を利用してサポートされています。 Unixソケットを利用する場合、LMTPは通常認証をサポートしたり要求したりはしません。しかし、あなたが必要であれば、利用することができます。

  バージョン 2.6 で追加.

このモジュールの例外には次のものがあります:

exception `smtplib.``SMTPException`

  このモジュールで提供される全ての例外クラスのベースクラスです。

exception `smtplib.``SMTPServerDisconnected`

  この例外はサーバが突然コネクションを切断するか、もしくは `SMTP` インスタンスを生成する前にコネクションを張ろうとした場合に上げられます。

exception `smtplib.``SMTPResponseException`

  SMTPのエラーコードを含んだ例外のクラスです。これらの例外はSMTPサーバがエラーコードを返すときに生成されます。エラーコードは `smtp_code` 属性に格納されます。また、 `smtp_error` 属性にはエラーメッセージが格納されます。

exception `smtplib.``SMTPSenderRefused`

  送信者のアドレスが弾かれたときに上げられる例外です。全ての `SMTPResponseException` 例外に、 SMTPサーバが弾いた'sender'アドレスの文字列がセットされます。

exception `smtplib.``SMTPRecipientsRefused`

  全ての受取人アドレスが弾かれたときに上げられる例外です。各受取人のエラーは属性 `recipients` によってアクセス可能で、 `SMTP.sendmail()` が返す辞書と同じ並びの辞書になっています。

exception `smtplib.``SMTPDataError`

  SMTPサーバが、メッセージのデータを受け入れることを拒絶した時に上げられる例外です。

exception `smtplib.``SMTPConnectError`

  サーバへの接続時にエラーが発生した時に上げられる例外です。

exception `smtplib.``SMTPHeloError`

  サーバーが `HELO` メッセージを弾いた時に上げられる例外です。

exception `smtplib.``SMTPAuthenticationError`

  SMTP 認証が失敗しました。最もあり得る可能性は、サーバーがユーザ名/パスワードのペアを受付なかった事です。

参考

RFC 821 - Simple Mail Transfer Protocol
  SMTP のプロトコル定義です。このドキュメントでは SMTP のモデル、操作手順、プロトコルの詳細についてカバーしています。
RFC 1869 - SMTP Service Extensions
  SMTP に対する ESMTP 拡張の定義です。このドキュメントでは、新たな命令による SMTP の拡張、サーバによって提供される命令を動的に発見する機能のサポート、およびいくつかの追加命令定義について記述しています。

## 20.12.1. SMTP オブジェクト

`SMTP` クラスインスタンスは次のメソッドを提供します:

`SMTP.``set_debuglevel`(level)

  コネクション間でやりとりされるメッセージ出力のレベルをセットします。メッセージの冗長さは level に応じて決まります。

`SMTP.``docmd`(cmd[, argstring])

  サーバへコマンド cmd を送信します。オプション引数 argstring はスペース文字でコマンドに連結します。

  戻り値は、整数値のレスポンスコードと、サーバからの応答の値をタプルで返します。 (サーバからの応答が数行に渡る場合でも一つの大きな文字列で返します。)

  通常、この命令を明示的に使う必要はありませんが、自分で拡張するする時に使用するときに役立つかもしれません。

  応答待ちのときに、サーバへのコネクションが失われると、 `SMTPServerDisconnected` が上がります。

`SMTP.``connect`([host[, port]])

  ホスト名とポート番号をもとに接続します。デフォルトはlocalhostの標準的なSMTPポート(25番)に接続します。もしホスト名の末尾がコロン(`':'`)で、後に番号がついている場合は、「ホスト名:ポート番号」として扱われます。このメソッドはコンストラクタにホスト名及びポート番号が指定されている場合、自動的に呼び出されます。戻り値は、この接続の応答内でサーバによって送信された応答コードとメッセージの2要素タプルです。

`SMTP.``helo`([hostname])

  SMTPサーバに `HELO` コマンドで身元を示します。デフォルトではhostname引数はローカルホストを指します。サーバーが返したメッセージは、オブジェクトの `helo_resp` 属性に格納されます。

  通常は `sendmail()` が呼びだすため、これを明示的に呼び出す必要はありません。

`SMTP.``ehlo`([hostname])

  `EHLO` を利用し、ESMTPサーバに身元を明かします。デフォルトではhostname引数はローカルホストのFQDNです。また、ESMTPオプションのために応答を調べたものは、 `has_extn()` に備えて保存されます。また、幾つかの情報を属性に保存します: サーバーが返したメッセージは `ehlo_resp` 属性に、 `does_esmtp` 属性はサーバーがESMTPをサポートしているかどうかによって true か false に、 `esmtp_features` 属性は辞書で、サーバーが対応しているSMTP サービス拡張の名前と、もしあればそのパラメータを格納します。

  `has_extn()` をメールを送信する前に使わない限り、明示的にこのメソッドを呼び出す必要があるべきではなく、 `sendmail()` が必要とした場合に呼ばれます。

`SMTP.``ehlo_or_helo_if_needed`()

  このメソッドは、現在のセッションでまだ `EHLO` か `HELO` コマンドが実行されていない場合、 `ehlo()` and/or `helo()` メソッドを呼び出します。このメソッドは先に ESMTP `EHLO` を試します。

  `SMTPHeloError`
    サーバーが `HELO` に正しく返事しなかった.

  バージョン 2.6 で追加.

`SMTP.``has_extn`(name)

  name が拡張SMTPサービスセットに含まれている場合には `True` を返し、そうでなければ `False` を返します。大小文字は区別されません。

`SMTP.``verify`(address)

  `VRFY` を利用してSMTPサーバにアドレスの妥当性をチェックします。妥当である場合はコード250と完全な RFC 822 アドレス(人名)のタプルを返します。それ以外の場合は、400以上のエラーコードとエラー文字列を返します。

  注釈

  ほとんどのサイトはスパマーの裏をかくためにSMTPの `VRFY` は使用不可になっています。

`SMTP.``login`(user, password)

  認証が必要なSMTPサーバにログインします。認証に使用する引数はユーザ名とパスワードです。まだセッションが無い場合は、 `EHLO` または `HELO` コマンドでセッションを作ります。ESMTPの場合は `EHLO` が先に試されます。認証が成功した場合は通常このメソッドは戻りますが、例外が起こった場合は以下の例外が上がります:

  `SMTPHeloError`
    サーバーが `HELO` に正しく返事しなかった.
  `SMTPAuthenticationError`
    サーバがユーザ名/パスワードでの認証に失敗した。
  `SMTPException`
    どんな認証方法も見付からなかった。

`SMTP.``starttls`([keyfile[, certfile]])

  TLS(Transport Layer Security)モードでSMTPコネクションを出し、全てのSMTPコマンドは暗号化されます。これは `ehlo()` をもう一度呼びだすときにするべきです。

  keyfile と certfile が提供された場合に、 `socket` モジュールの `ssl()` 関数が通るようになります。

  もしまだ `EHLO` か `HELO` コマンドが実行されていない場合、このメソッドは ESMTP `EHLO` を先に試します。

  バージョン 2.6 で変更.

  `SMTPHeloError`
    サーバーが `HELO` に正しく返事しなかった.
  `SMTPException`
    サーバーが STARTTLS 拡張に対応していない。

  バージョン 2.6 で変更.

  `RuntimeError`
    実行中の Python インタプリタで、SSL/TLS サポートが利用できない。

`SMTP.``sendmail`(from_addr, to_addrs, msg[, mail_options, rcpt_options])

  メールを送信します。必要な引数は RFC 822 のfromアドレス文字列、 RFC 822 のtoアドレス文字列またはアドレス文字列のリスト、メッセージ文字列です。送信側は `MAIL FROM` コマンドで使用される mail_options の ESMTPオプション(`8bitmime` のような)のリストを得るかもしれません。全ての `RCPT` コマンドで使われるべきESMTPオプション (例えば `DSN` コマンド)は、 rcpt_options を通して利用することができます。(もし送信先別にESMTPオプションを使う必要があれば、メッセージを送るために `mail()` 、 `rcpt()` 、 `data()` といった下位レベルのメソッドを使う必要があります。)

  注釈

  配送エージェントは from_addr 、 to_addrs 引数を使い、メッセージのエンベロープを構成します。 `SMTP` はメッセージヘッダを修正しません。

  まだセッションが無い場合は、 `EHLO` または `HELO` コマンドでセッションを作ります。ESMTPの場合は `EHLO` が先に試されます。また、サーバがESMTP対応ならば、メッセージサイズとそれぞれ指定されたオプションも渡します。(featureオプションがあればサーバの広告をセットします) `EHLO` が失敗した場合は、ESMTPオプションの無い `HELO` が試されます。

  このメソッドは最低でも1つの受信者にメールが受け入れられたときは普通に戻りますが、そうでない場合は例外を投げます。このメソッドが例外を投げられなければ、誰かが送信したメールを得るべきです。また、例外を投げれなかった場合は、拒絶された受取人ごとへの1つのエントリーと共に、辞書を返します。各エントリーは、サーバーによって送られたSMTPエラーコードおよびエラーメッセージのタプルを含んでいます。

  このメソッドは次の例外を上げることがあります:

  `SMTPRecipientsRefused`
    全ての受信を拒否され、誰にもメールが届けられませんでした。例外オブジェクトの `recipients` 属性は、受信拒否についての情報の入った辞書オブジェクトです。 (辞書は少なくとも一つは受信されたときに似ています)。
  `SMTPHeloError`
    サーバーが `HELO` に正しく返事しなかった.
  `SMTPSenderRefused`
    サーバが from_addr を受理しませんでした。
  `SMTPDataError`
    サーバが予期しないエラーコードを返しました (受信拒否以外)。

  また、この他の注意として、例外が上がった後もコネクションは開いたままになっています。

`SMTP.``quit`()

  SMTPセッションを終了し、コネクションを閉じます。 SMTP `QUIT` コマンドの結果を返します。

  バージョン 2.6 で変更: 結果を返すようになりました

下位レベルのメソッドは標準SMTP/ESMTPコマンド `HELP` 、 `RSET` 、 `NOOP` 、 `MAIL` 、 `RCPT` 、 `DATA` に対応しています。通常これらは直接呼ぶ必要はなく、また、ドキュメントもありません。詳細はモジュールのコードを調べてください。

## 20.12.2. SMTP 使用例

次の例は最低限必要なメールアドレス('To' と 'From')を含んだメッセージを送信するものです。この例では RFC 822 ヘッダの加工もしていません。メッセージに含まれるヘッダは、メッセージに含まれる必要があり、特に、明確な'To'、と'From'アドレスはメッセージヘッダに含まれている必要があります。

    import smtplib

    def prompt(prompt):
        return raw_input(prompt).strip()

    fromaddr = prompt("From: ")
    toaddrs  = prompt("To: ").split()
    print "Enter message, end with ^D (Unix) or ^Z (Windows):"

    # Add the From: and To: headers at the start!
    msg = ("From: %s\r\nTo: %s\r\n\r\n"
           % (fromaddr, ", ".join(toaddrs)))
    while 1:
        try:
            line = raw_input()
        except EOFError:
            break
        if not line:
            break
        msg = msg + line

    print "Message length is " + repr(len(msg))

    server = smtplib.SMTP('localhost')
    server.set_debuglevel(1)
    server.sendmail(fromaddr, toaddrs, msg)
    server.quit()

注釈

多くの場合、 `email` パッケージの機能を使って email メッセージを構築し、それを文字列に変換して、 `sendmail()` で送信する、という手順を用います。 email: 使用例 を参照してください。