回答編集履歴
4
微修正
test
CHANGED
@@ -76,7 +76,7 @@
|
|
76
76
|
|
77
77
|
質問者さんはすでに解決したようですが、改めて書くと、現実には、実際のファイルの内容が想定したキャラクタセットで符号化できるものだとは限らないからです。今回の場合、半角片仮名が含まれています。
|
78
78
|
|
79
|
-
ISO-2022-JPの符号化をするコデックは本来、半角片仮名を符号化することができません。しかし、「半角片仮名も使えるようにしようぜ」と考えて独自の方法で符号化できるようにしたコデックの実装も存在してしまっているのが現実です。それらのコデックの符号化方式には互換性がないので、一旦文字列に変換してから符号化すると、元のファイルと違う
|
79
|
+
ISO-2022-JPの符号化をするコデックは本来、半角片仮名を符号化することができません。しかし、「半角片仮名も使えるようにしようぜ」と考えて独自の方法で符号化できるようにしたコデックの実装も存在してしまっているのが現実です。それらのコデックの符号化方式には互換性がないので、一旦文字列に変換してから符号化すると、元のファイルと違うバイト列になってしまうかもしれません。
|
80
80
|
|
81
81
|
MIMETextのインスタンスを作るときに文字列ではなくバイト列を与えると、コデックによる変換をせずにバイト列そのままを符号化されたメッセージに入れてくれます。この場合、open()でファイルを開くときはbフラグを指定してバイト列のままを読み出す必要がありますね。
|
82
82
|
|
3
残りを書きました
test
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
(途中まで回答します。残りは明日以降)
|
2
1
|
まず、**電子メールの内容は文字列ではありません**。このことを簡単に説明します(分かっている人は「本題。」のところまで読み飛ばしてください)。
|
3
2
|
|
4
3
|
メールを読み書きする人々にとってはたしかにそうで、電子メールはそのほとんどが文字列 (テキストデータ) でできています。しかしプログラマにとっては違います。彼らにとって電子メールというのは、通信回線で伝送されたりサーバのディスクに保存されたりする**バイト列**です。
|
@@ -29,13 +28,13 @@
|
|
29
28
|
|
30
29
|
`body`の文字列を本文に持ち、`path`の場所に保存したファイルを添付したマルチパートのメッセージを作ろうというのですね。
|
31
30
|
|
32
|
-
`
|
31
|
+
`MIMEText`クラスは"text" MIME型を持つメッセージパートを表すクラスですから、本文の方はこれでいいです。いっぽうMIMEには個々のメッセージパートに「本文」とそれ以外の「添付」という区別はありません。だから添付のほうも同じく`MIMEText`クラスを使えばいいでしょう。
|
33
32
|
|
34
33
|
上で説明したように、元になるテキストデータは文字列なので、本文でも添付でもstr型のデータを使わなければなりません。`open()`でテキストモードを明示的に指定しているのは、バイト列であるファイルの内容を読み出して文字列に変換しているのですから、これで正しいですね。
|
35
34
|
|
36
35
|
しかし、`encode_base64()`を使って添付のペイロードをBASE64で伝送符号化しようとしています。この意図はいいのですが、BASE64はバイト列をバイト列に符号化する変換です。文字列 (str) を渡したので、これはうまく動かないでしょう。
|
37
36
|
|
38
|
-
実は、`
|
37
|
+
実は、`MIMEText`クラスで`charset`パラメータを指定してインスタンスを作った場合、最終的なメッセージ全体の符号化の際に伝送符号化を適切に判断してやってくれます (と、emailパッケージのソースに書いてありました)。だからここで伝送符号化しなくていいでしょう。
|
39
38
|
|
40
39
|
以上のことを元に、この部分を書き直してみたのが以下です (ほかにもちょっと変えました)。
|
41
40
|
|
@@ -73,6 +72,13 @@
|
|
73
72
|
|
74
73
|
---
|
75
74
|
|
76
|
-
しかし、キャラクタセットを`utf-8`から`iso-2022-jp`に変えたところ、UnicodeEncodeError例外が発生してしまうということでした。
|
75
|
+
しかし、キャラクタセットを`utf-8`から`iso-2022-jp`に変えたところ、UnicodeEncodeError例外が発生してしまうということでした。\[以下2019-04-03追記]
|
77
|
-
(続く)
|
78
76
|
|
77
|
+
質問者さんはすでに解決したようですが、改めて書くと、現実には、実際のファイルの内容が想定したキャラクタセットで符号化できるものだとは限らないからです。今回の場合、半角片仮名が含まれています。
|
78
|
+
|
79
|
+
ISO-2022-JPの符号化をするコデックは本来、半角片仮名を符号化することができません。しかし、「半角片仮名も使えるようにしようぜ」と考えて独自の方法で符号化できるようにしたコデックの実装も存在してしまっているのが現実です。それらのコデックの符号化方式には互換性がないので、一旦文字列に変換してから符号化すると、元のファイルと違う符号になってしまうかもしれません。
|
80
|
+
|
81
|
+
MIMETextのインスタンスを作るときに文字列ではなくバイト列を与えると、コデックによる変換をせずにバイト列そのままを符号化されたメッセージに入れてくれます。この場合、open()でファイルを開くときはbフラグを指定してバイト列のままを読み出す必要がありますね。
|
82
|
+
|
83
|
+
回答終わり。
|
84
|
+
|
2
動くように修正、追記
test
CHANGED
@@ -40,7 +40,14 @@
|
|
40
40
|
以上のことを元に、この部分を書き直してみたのが以下です (ほかにもちょっと変えました)。
|
41
41
|
|
42
42
|
```python
|
43
|
+
from email.mime.multipart import MIMEMultipart
|
43
|
-
from email.mime
|
44
|
+
from email.mime.multipart import MIMEText
|
45
|
+
|
46
|
+
text = '''
|
47
|
+
本文……
|
48
|
+
'''
|
49
|
+
path = '/path/to/attachment.txt'
|
50
|
+
filename = '添付ファイル.txt'
|
44
51
|
|
45
52
|
parent = MIMEMultipart()
|
46
53
|
body = MIMEText(text, 'plain', 'utf-8')
|
@@ -56,6 +63,14 @@
|
|
56
63
|
|
57
64
|
これでうまくいくのではないでしょうか。わたしはちゃんと確認できていないので、確認してみてください。
|
58
65
|
|
66
|
+
\[2019-04-03追記]
|
67
|
+
|
68
|
+
```python
|
69
|
+
smtp.sendmail(from_address, to_address + bcc_addrs, parent.as_string())
|
70
|
+
```
|
71
|
+
|
72
|
+
ここですが、「電子メールはバイト列である」という原則からすると`as_string()`じゃなくて`as_bytes()`じゃないの? と思うかもしれません。実際、`as_bytes()`もあるのでそっちを使ってもかまいません。両者はデフォルトでは同じ結果を出します (結果が文字列かバイト列かの違いだけで、どちらもASCIIの範囲の文字/バイトを使う)。が、as\_string()は`utf8`ポリシが有効だと違う結果になります。
|
73
|
+
|
59
74
|
---
|
60
75
|
|
61
76
|
しかし、キャラクタセットを`utf-8`から`iso-2022-jp`に変えたところ、UnicodeEncodeError例外が発生してしまうということでした。次は、これについて考えてみます。
|
1
微修正
test
CHANGED
@@ -10,6 +10,8 @@
|
|
10
10
|
プログラムで電子メールを作成するには、文字列やバイト列を元に、最終的にバイト列を作成する必要があります。ここまでの説明を前提に、ご質問に回答していきます。
|
11
11
|
|
12
12
|
---
|
13
|
+
|
14
|
+
本題。
|
13
15
|
|
14
16
|
```python
|
15
17
|
parent = MIMEMultipart()
|