82362


複数の人にメールを自動送信するためのプログラムを書いています。

### 概要

  * Python の smtplib モジュールを使用し、複数の宛先にメールを自動送信するコードを作成。
  * 宛先のメールアドレスリスト一覧が記載されたcsvファイルを読み込み、一行ずつループ処理で、message['To']に指定し、送信。
  * 何度か送信テストを実施して、送信自体は成功している。

### 達成したいこと

メールが正常に送信できたのか、それとも何かエラーが起き、送信が正常に完了しなかったか、を1通ごとに把握したい。以下のようなイメージで、ターミナルにログを出力したい。

[code]

    2021-09-07 11:56:23 Email to example@gmail.com status: success
    2021-09-07 11:56:29 Email to error@gmail.com status: failure
    
[/code]

### 試したこと

Pythonのドキュメントを調べ、`SMTP.set_debuglevel()` というものがあることを知り、コードに組み込んだ。

### 今悩んでいること

`SMTP.set_debuglevel()`
の出力内容が理解できず、どのようにすれば、メール送信の成功、不成功、といった情報を、1通ごとに全て出力できるのか、わからない。

[code]

    message = EmailMessage()
    message['Subject'] = 'タイトル'
    message['From'] = EMAIL_ADDRESS
    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
          smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
          for row in reader:
            message['To'] = row[0]
            message.set_content('メッセージ本文')        
            smtp.send_message(message)
            smtp.set_debuglevel(True)
    
[/code]

ご教示いただけますと幸いです。


CC BY-SA 4.0
2021-09-08T10:58:53.997
82352
2021-09-09T03:49:35.960
2021-09-09T01:40:16.327
3060
48114
question
python smtplib
Pythonのsmtplibでメールを送信する際に、ログをターミナルに出力したい


Shin さん:

> 例えばメールアドレスの入力ミスがあった場合は、送信元アドレスへMail Delivery Subsystemより、Delivery Status
> Notification
> (Failure)という通知がきますが、相手先の受信サーバへメールを届けようとした際に何かエラーが発生したかどうかは、このNotificationのみによって感知できるということでしょうか？

私:

> はい、その通りです。

`smtp.send_message()` を実行する際に発生する可能性のある `smtplib.SMTPException` を例外処理(`try ~
except`)で検出します。

[code]

    import sys
    from datetime import datetime
    
    message = EmailMessage()
    message['Subject'] = 'タイトル'
    message['From'] = EMAIL_ADDRESS
    # 同じメッセージ本文であればここで定義してもよいはず
    message.set_content('メッセージ本文')
    
    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
          #smtp.set_debuglevel(True)
          smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
          for row in reader:
            message['To'] = row[0]
    
            status = 'success'
            try:
                smtp.send_message(message)
            except smtplib.SMTPException:
                status = 'failure'
            finally:
                now = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
                print(f'{now} Email to {message["To"]} status: {status}', file=sys.stderr)
            del message['To']
    
[/code]

例えば質問文にある `error@gmail.com` に送信してみると、

> `2021/09/09 09:39:05 Email to error@gmail.com status: success`

と表示されますが、この後に `Mail From`(もしくは `Return-Path`)に設定したメールアドレスに以下の様なメールが届きます。

> Subject: Delivery Status Notification (Failure)  
>  Auto-Submitted: auto-replied
>
> ** アドレス不明 **
>
> アドレスが見つからなかったか、メールを受信できないアドレスであるため、メールは error@gmail.com に配信されませんでした。
>
> 詳細: <https://support.google.com/mail/?p=NoSuchUser>
>
> 応答:
>
> 550 5.1.1 The email account that you tried to reach does not exist. Please
> try double-checking the recipient's email address for typos or unnecessary
> spaces. Learn more at <https://support.google.com/mail/?p=NoSuchUser>

`error@gmail.com` に送信した場合の SMTP サーバとのやり取りは以下になります(必要な部分だけを抜き出して記載しています)。

[code]

    send: mail FROM:<...> size=212
    reply: 250 2.1.0 OK
    send: rcpt TO:<error@gmail.com>
    reply: 250 2.1.5 OK
    send: data
    reply: 354 Go ahead
    send: Content-Type: text/plain; charset="utf-8" ...
    reply: 250 2.0.0 OK  1631147944
    
    # これは前述の Python スクリプトが表示しています
    2021/09/09 09:39:05 Email to error@gmail.com status: success
    
    send: QUIT
    reply: 221 2.0.0 closing connection
    
[/code]

それでは `SMTPException`
が発生するのはどの様な場合かと言えば、例えばメールアドレスが非正規な形式になっている場合です。一例としてドメイン名を指定しないアドレス宛に送信してみます。

メールアドレス `error` 宛に送信

[code]

    send: mail FROM:<...> size=202
    reply: 250 2.1.0 OK
    send: rcpt TO:<error>
    reply: 553 5.1.3 The recipient address <error> is not a valid RFC-5321 address.
    send: rset
    reply: 250 2.1.5 Flushed
    
    2021/09/09 09:56:46 Email to error status: failure
    
    send: QUIT
    reply: 221 2.0.0 closing connection
    
[/code]

まぁ、後から届く `Delivery Status Notification (Failure)`
のメールを自動的にチェックして…などという事も考えられなくはないですが、面倒ではありますね。。。


CC BY-SA 4.0
2021-09-09T01:11:17.127
82362
2021-09-09T03:49:35.960
2021-09-09T03:49:35.960
47127
47127
82352
answer