いろいろ試しました。
先に結論を言ってしまうと、基本的には、文字化けないように出来ててあんまり考えなくていいです。あと、Python3でadd_charsetで文字セットいじったときの挙動がよく分かりません。
本題です。
##基本のコード
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email import charset
con = smtplib.SMTP('localhost')
con.set_debuglevel(True)
cset = 'utf-8' # <---------------(文字セットの設定だよ)
message = MIMEText(u'日本語のメールだよ★', 'plain', cset)
message['Subject'] = Header(u'メール送信テスト', cset)
message['From'] = 'from@example.com'
message['To'] = 'to@example.com'
con.sendmail('from@example.com', ['to@example.com'],
message.as_string())
con.close()
ではやってみます。
##Python2.7.2 + None
いきなり変化球だけど、文字セットの設定をしなかった場合を試す。
基本のコードで、cset = None
ってしてみた。
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-9: ordinal not in range(128)
さすがに怒られる。文字セットは何かしら登録しないと、us-ascii として処理されるので、どこかでコケます。
##Python2.7.2 + utf-8 (with BASE64)
基本のコードでcset = utf-8
ってしてみる。これは無事受信できました。
生データはこんなかんじ。
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Subject: =?utf-8?b?44Oh44O844Or6YCB5L+h44OG44K544OI?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
5pel5pys6Kqe44Gu44Oh44O844Or44Gg44KI4piF
BodyのエンコードがBase64になる。
これは、Pythonの標準が以下のようになってるから。
CHARSETS = {
...
'utf-8': (SHORTEST, BASE64, 'utf-8'),
#タプルは、ヘッダーのエンコード, ボディのエンコード、出力のエンコードを示してるんだってさcharset.pyに書いてあった
…
}
多分、これで困ることってもう殆ど無いんだけど、昔は、auの端末でNGでした確か。でももうこれでいいと思います。おしまい。
##Python2.7.2 + utf-8 with QP
Base64が嫌だ! って場合は、CHARSETを上書きする。
これを基本のコードの最初のほうに挿入。
charset.add_charset('utf-8', charset.SHORTEST, charset.QP, 'utf-8')
# uft-8 の設定として、 ヘッダはSHORTEST、ボディにQP(quoted-printable)使うよ、出力のエンコードはutf-8だよ
cset = utf-8
これを実行するとこうなる。
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Subject: =?utf-8?b?44Oh44O844Or6YCB5L+h44OG44K544OI?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
=E6=97=A5=E6=9C=AC=E8=AA=9E=E3=81=AE=E3=83=A1=E3=83=BC=E3=83=AB=E3=81=A0=E3=
=82=88=E2=98=85
BASE64じゃない何かになってます。
受信も問題ないです。
##Python2.7.2 + utf-8 with 8bit
ボディのエンコードに何も指定しないとどうなるか。
charset.add_charset('utf-8', charset.SHORTEST, None, 'utf-8')
cset = utf-8
出力はこう。そのまま出る。
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject: =?utf-8?b?44Oh44O844Or6YCB5L+h44OG44K544OI?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
日本語のメールだよ★
Content-Transfer-Encodingは7bitか8bitになる。
これは、/email/encoders.py の
encode_7or8bit() という関数がうまいこと決定している。
8bitにしたいなーと思う場合は、これ。これが結構最近多いのかも。
##Python2.7.2 + shift_jis
IME-Version: 1.0
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit
Subject: =?iso-2022-jp?b?GyRCJWEhPCVrQXc/LiVGJTklSBsoQg==?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
F|K\8l$N%a!<%k$@$h!z
文字セットを'shift_jis'とすると、出力はみんな大好きiso-2022-jpになりました。
これは、Pythonの標準設定がこうn
'shift_jis': (BASE64, None, 'iso-2022-jp'),
BodyのエンコーディングがNoneになってる。Content-Transfer-Encodingは勝手に 7bit ってなってる。
##Python3.3.0 + None
次、Python3 で試す。最初に、文字セットを指定しない場合。Python2だとUnicodeEncodeErrorが出たやつ。
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Subject: =?utf-8?b?44Oh44O844Or6YCB5L+h44OG44K544OI?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
5pel5pys6Kqe44Gu44Oh44O844Or44Gg44KI4piF
なんと送れる。受信も問題ない。
ちょっと中身読んだ感じ、us-ascii で試して、UnicodeEncodeErrorが出たらutf-8で試す、っていう感じっぽい。
ということで、Python3.3 だと、文字セットを全く意識しなくてもメール飛ばせるのですごい。
##Python3.3.0 + utf-8 (with BASE64)
ということで、cset = utf-8
とやっても、上と同じ筈。
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Subject: =?utf-8?b?44Oh44O844Or6YCB5L+h44OG44K544OI?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
5pel5pys6Kqe44Gu44Oh44O844Or44Gg44KI4piF
同じ! 次!
##Python3.3.0 + utf-8 with QP
BODYにQP使ってみた〜い!
ってことで、Python2のときと同じく下をどっかに書く。
charset.add_charset('utf-8', charset.SHORTEST, charset.QP, 'utf-8')
cset = utf-8
メール送信!
self.set_payload(_text, _charset)
File "/Users/yasunori/.pythonbrew/pythons/Python-3.3.0/Frameworks/Python.framework/Versions/3.3/lib/python3.3/email/message.py", line 280, in set_payload
self.set_charset(charset)
File "/Users/yasunori/.pythonbrew/pythons/Python-3.3.0/Frameworks/Python.framework/Versions/3.3/lib/python3.3/email/message.py", line 317, in set_charset
self._payload = charset.body_encode(self._payload)
File "/Users/yasunori/.pythonbrew/pythons/Python-3.3.0/Frameworks/Python.framework/Versions/3.3/lib/python3.3/email/charset.py", line 395, in body_encode
return email.quoprimime.body_encode(string)
File "/Users/yasunori/.pythonbrew/pythons/Python-3.3.0/Frameworks/Python.framework/Versions/3.3/lib/python3.3/email/quoprimime.py", line 240, in body_encode
if body_check(ord(c)):
File "/Users/yasunori/.pythonbrew/pythons/Python-3.3.0/Frameworks/Python.framework/Versions/3.3/lib/python3.3/email/quoprimime.py", line 81, in body_check
return chr(octet) != _QUOPRI_BODY_MAP[octet]
KeyError: 26085
怒られたー! 怖い怖い怖い怖い!!!!
配列にそんなキー無いって言われてる。見た感じ、_QUOPRI_BODY_MAP は英数字程度の筈なのに、26085番目の文字を参照しようとしてる。
なんでだろう…… ちょっと見た感じではよく分からないので保留。
##Python3.3.0 + utf-8 with 8bit
8bitでそのまま送りたいのねん。
charset.add_charset('utf-8', charset.SHORTEST, None, 'utf-8')
こいつを追加して送信。
File "/Users/yasunori/.pythonbrew/pythons/Python-3.3.0/Frameworks/Python.framework/Versions/3.3/lib/python3.3/smtplib.py", line 744, in sendmail
msg = _fix_eols(msg).encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 231-240: ordinal not in range(128)
怒られたー! 怖い怖い怖い怖い!!!!
何でこれ怒られるんでしょう。
実は、QPのエラーと違って、message.as_string()
までは通っていて、メール文面まではちゃんと出来ている。
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject: =?cp932?b?g4GBW4OLkZeQTYNlg1iDZw==?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
日本語のメールだよ★
いいじゃん。
いざ送信! ってときに怒られてるんだよなー。
さっきのエラー箇所を見ると、smtplibの中で、asciiべた書きでencodeしようとしてるので確かに駄目っぽいんだけど…… これってどうすればいいんだろう。誰か教えてください……
##Python3.3.0 + shift_jis
安定のsjis。
MIME-Version: 1.0
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit
Subject: =?iso-2022-jp?b?GyRCJWEhPCVrQXc/LiVGJTklSBsoQg==?=
From: from@example.com
To: to@example.com
Reply-To: somebody@example.com
F|K\8l$N%a!<%k$@$h!z
##おしまい
大体想像通りの動きをしてくれますが、Python3系で、add_charset したときの挙動がかなり不審でいまのところ鬼門です。やり方間違ってる??