2012-02-22 40 views
7

我想在Python 3.2程序中發送具有任意unicode主體的電子郵件。但是,實際上,這些消息主要由7位ASCII文本組成。所以我想用uted-8使用quoted-printable編碼的消息。到目前爲止,我發現這個工作,但它似乎是錯誤的:如何使用Python 3.2電子郵件模塊發送帶有quoted-printable的utf-8編碼的unicode消息?

c = email.charset.Charset('utf-8') 
c.body_encoding = email.charset.QP 
m = email.message.Message() 
m.set_payload("My message with an '\u05d0' in it.".encode('utf-8').decode('iso8859-1'), c) 

這將導致電子郵件消息完全正確的內容:

To: [email protected] 
From: [email protected] 
Subject: This is a subjective subject. 
MIME-Version: 1.0 
Content-Type: text/plain; charset="utf-8" 
Content-Transfer-Encoding: quoted-printable 

My message with an '=D7=90' in it. 

特別b'\xd7\x90'.decode('utf-8')結果在原來的Unicode字符。所以quoted-printable編碼正確地呈現utf-8。我很清楚這是一個令人難以置信的醜陋黑客。但它的工作。

這是Python 3.預計文本字符串始終是unicode。我不應該將它解碼爲utf-8。然後將它從bytes轉換回str.decode('iso8859-1')是一個可怕的黑客攻擊,我不應該這樣做。

它的email模塊就編碼而言剛剛破裂?我沒有得到什麼嗎?

我試圖只是簡單的老設置它,沒有字符集。這給我留下了一個unicode電子郵件信息,這根本就不對。我也嘗試過關閉encodedecode的步驟。如果我將它們都關閉,它會在嘗試確定該字符是否需要用quoted-printable編碼引用時抱怨\u05d0超出範圍。如果我只在encode步驟中離開,它會非常抱怨我如何通過bytes,並且它想要str

+0

如果'「我在它的‘\ u05d0’的消息。」'是你想要的,那麼你就不能使用'「我的消息在‘\ u05d0’unicode的「。encode('utf-8')。decode('iso8859-1')'因爲這是一個不同的unicode。 (你會改變這個消息。) – unutbu 2012-02-22 21:52:49

+0

@unutbu:恭喜你發現代碼非常醜陋的原因。但它的工作。它達到了預期的結果。查看我的更新。 – Omnifarious 2012-02-22 21:58:57

回答

8

該電子郵件軟件包對哪個(編碼的Unicode與內容傳輸編碼的二進制數據)沒有混淆,但文檔沒有說清楚,因爲大部分文檔都是從「編碼「意味着內容傳輸編碼。我們正在研究一個更好的API,這將使所有這些更容易理解(和更好的文檔)。

實際上有一種方法可以讓電子郵件包使用QP用於utf-8機構,但它沒有很好的記錄。你不喜歡這樣:

>>> charset.add_charset('utf-8', charset.QP, charset.QP) 
>>> m = MIMEText("This is utf-8 text: á", _charset='utf-8') 
>>> str(m) 
'Content-Type: text/plain; charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\n\nThis is utf-8 text: =E1' 
+0

謝謝!這完美地回答了我的問題,併爲我提供了一種做我想做的事情的方式,這不是一件令人不安的事情。 :-) – Omnifarious 2012-03-03 01:43:06

+1

處理你的角色就好了。但它不處理字符\ u05d0。實際上,它不會將您的字符編碼爲utf-8,而是將其編碼爲iso8859-1。 : -/ – Omnifarious 2012-03-03 01:50:32

+0

另請參閱Python [issue1525919](http://bugs.python.org/issue1525919#msg29229)。 – mmoya 2013-05-28 13:01:33

1

運行

import email 
import email.charset 
import email.message 

c = email.charset.Charset('utf-8') 
c.body_encoding = email.charset.QP 
m = email.message.Message() 
m.set_payload("My message with an '\u05d0' in it.", c) 
print(m.as_string()) 

此息率回溯消息:

File "/usr/lib/python3.2/email/quoprimime.py", line 81, in body_check 
    return chr(octet) != _QUOPRI_BODY_MAP[octet] 
KeyError: 1488 

由於

In [11]: int('5d0',16) 
Out[11]: 1488 

很顯然,unicode的'\u05d0'是問題人物。 _QUOPRI_BODY_MAPquoprimime.py

_QUOPRI_HEADER_MAP = dict((c, '=%02X' % c) for c in range(256)) 
_QUOPRI_BODY_MAP = _QUOPRI_HEADER_MAP.copy() 

此字典只包含來自range(256)鍵定義。所以我認爲你是對的; quoprimime.py不能用於編碼任意的Unicode。

作爲一種變通方法,您可以通過省略

c.body_encoding = email.charset.QP 

注意quoprimime.py的latest version不使用_QUOPRI_BODY_MAP可言,所以使用最新的Python可能會解決使用(默認值)的base64問題。

+2

我懷疑它不會。在應用quoted-printable編碼之前,問題似乎沒有正確轉換爲utf-8字節。 'email.message.Message'的'as_string'和'__str__'方法應該被棄用,而不是使用返回字節的方法。我猜想整個電子郵件包對電子郵件消息上的二進制編碼和使用特定字符編碼系統所暗示的編碼之間的區別有點混淆。這兩個實際上是分開的概念,即使它們都使用術語'編碼'。 – Omnifarious 2012-02-22 22:11:04

相關問題