質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.01%

Python3でメール送信(文字コードエラー)

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,459

tosmame

score 9

 Python3でメール送信(文字コードエラー)

Python3でメール送信(送信先複数)が出来るようにしたいです。
実装したいのは「件名・本文が書かれているテキストファイルを読み込み、その内容を送信」といった機能です。

現在、件名・タイトルのいずれかに日本語を使用するとエラーが起きてしまいます。

 エラーメッセージ

Traceback (most recent call last):
  File "sendmailer.py", line 50, in <module>
    sendmail.sendmail("BBB@example.com,CCC@example.com")
  File "sendmailer.py", line 28, in sendmail
    result = smtp.sendmail( self.sender, recipients_text.split(','), message_body )  # メールの送信
  File "C:\Users\---\AppData\Local\Programs\Python\Python36-32\lib\smtplib.py", line 855, in sendmail
    msg = _fix_eols(msg).encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 106-108: ordinal not in range(128)

 該当のソースコードとテキストファイル

import smtplib
from smtplib import SMTPException

class SendMail:
    def __init__(self, sender, subject, contents):
        self.sender = sender
        self.subject = subject
        self.contents = contents

    def sendmail(self, recipients_text):
        # 接続先 SMTP サーバの定義
        smtp = smtplib.SMTP('smtp.office365.com', 587)  # FQDN とポート番号
        # 認証情報の定義
        user = self.sender  # SMTP サーバに接続するためのユーザ
        password = "password"

        # SMTP サーバへの接続とメールの送信
        try:
            smtp.ehlo()
            smtp.starttls()  # TLS の開始(以降の通信は暗号化される) 
            smtp.ehlo()
            smtp.login(user, password)  # SMTP サーバにログイン
            #ヘッダー
            header = 'To:' + recipients_text + '\n' + 'From: ' + self.sender + '\n' + 'Subject:' + self.subject + '\n'
            #本文
            message_body = header + '\n' + self.contents + '\n\n'

            result = smtp.sendmail( self.sender, recipients_text.split(','), message_body )  # メールの送信
            smtp.quit()  # SMTP セッションの終了と TCP コネクションの切断
        except smtplib.SMTPException as e:
            print("エラーが起きました!送信できません")



#送信者アドレス・送信内容
f = open("mail_content.txt", encoding='utf-8')
#1行目はスキップ
file_contents = f.readlines()
#送信者メールアドレス・件名・本文をテキストファイルから読み込み
Sender = file_contents[1]
Sender = Sender.rstrip("\n")
Subject = file_contents[2]
Subject = Subject.rstrip("\n")
Contents = ""
for i in range(3, len(file_contents)):
    Contents = Contents + file_contents[i]
f.close()

sendmail = SendMail(Sender, Subject, Contents)
sendmail.sendmail("BBB@example.com","CCC@example.com")
送信者、件名、内容の順番
AAA@example.com
件名
本文

試したこと

>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

 補足情報

Python: 3.6.5
テキストファイルの文字コードはUTF-8(BOMなし)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

エラーメッセージから察するに、 smtplib のエンコーディング処理で転んでいるようですね。

おそらくこんな感じに書き換えると良いかと思います。
Diffフォーマットで示します。
緑色でマーキングされている部分が追記した行、赤色(ピンク色)でマーキングされている部分が削除した行です。

申し訳ありませんが、動作検証はしておりませんので要参考資料参照でお願いします。

import smtplib
from smtplib import SMTPException
+ from email.mime.text import MIMEText

class SendMail:
    def __init__(self, sender, subject, contents):
        self.sender = sender
        self.subject = subject
        self.contents = contents

    def sendmail(self, recipients_text):
        # 接続先 SMTP サーバの定義
        smtp = smtplib.SMTP('smtp.office365.com', 587)  # FQDN とポート番号
        # 認証情報の定義
        user = self.sender  # SMTP サーバに接続するためのユーザ
        password = "password"

        # SMTP サーバへの接続とメールの送信
        try:
            smtp.ehlo()
            smtp.starttls()  # TLS の開始(以降の通信は暗号化される) 
            smtp.ehlo()
            smtp.login(user, password)  # SMTP サーバにログイン
            #ヘッダー
            header = 'To:' + recipients_text + '\n' + 'From: ' + self.sender + '\n' + 'Subject:' + self.subject + '\n'
            #本文
-            message_body = header + '\n' + self.contents + '\n\n'
+            message_body = MINEText(header + '\n' + self.contents + '\n\n')

            result = smtp.sendmail( self.sender, recipients_text.split(','), message_body )  # メールの送信
            smtp.quit()  # SMTP セッションの終了と TCP コネクションの切断
        except smtplib.SMTPException as e:
            print("エラーが起きました!送信できません")

 参考資料

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/30 17:30 編集

    ご解答ありがとうございます。
    ご紹介いただいた方法では解消はしなかったものの、エラー解消につながる新しい視点を得ることが出来ましたのでベストアンサーとさせて頂きます。

    キャンセル

  • 2018/10/30 17:38

    コメントありがとうございます。

    クリティカルな回答ができず、申し訳ないです。
    ですが、エラー解消のきっかけになったようでなによりです。

    キャンセル

+1

プログラムを以下のように変更することで成功いたしました。
エラー処理等、不足している部分もありますのでこれから改善できればと思います。

import smtplib
from smtplib import SMTPException
from email.mime.text import MIMEText
from email.header import Header

class SendMail:

    def __init__(self, sender, subject, contents):
        self.sender = sender
        self.subject = subject
        self.contents = contents

    def sendmail(self, recipients_text):
        # 接続先 SMTP サーバの定義
        smtp = smtplib.SMTP('smtp.office365.com', 587)  # FQDN とポート番号
        # 認証情報の定義
        user = self.sender  # SMTP サーバに接続するためのユーザ
        password = "password"

        # SMTP サーバへの接続とメールの送信
        try:
            smtp.ehlo()
            smtp.starttls()  # TLS の開始(以降の通信は暗号化される) 
            smtp.ehlo()
            smtp.login(user, password)  # SMTP サーバにログイン

            encoding = 'utf-8'
            message = MIMEText( self.contents.encode( encoding ), 'plain', _charset=encoding )
            message['Subject'] = Header( self.subject, encoding )
            message['From'] = self.sender
            message['To'] = recipients_text

            result = smtp.sendmail( self.sender, recipients_text.split(','), message.as_string() )  # メールの送信
            smtp.quit()  # SMTP セッションの終了と TCP コネクションの切断
        except smtplib.SMTPException as e:
            print("エラーが起きました!送信できません")

#送信者アドレス・送信内容
f = open("mail_content.txt", encoding='utf-8')
#1行目はスキップ
file_contents = f.readlines()
#送信者メールアドレス・件名・本文をテキストファイルから読み込み
Sender = file_contents[1]
Sender = Sender.rstrip("\n")
Subject = file_contents[2]
Subject = Subject.rstrip("\n")
Contents = ""
for i in range(3, len(file_contents)):
    Contents = Contents + file_contents[i]
f.close()

sendmail = SendMail(Sender, Subject, Contents)
sendmail.sendmail("BBB@example.com","CCC@example.com")

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.01%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる