1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """Unicode email support (extends email from stdlib)"""
19
20 __docformat__ = "restructuredtext en"
21
22 import email
23 from encodings import search_function
24 import sys
25 if sys.version_info >= (2, 5):
26 from email.utils import parseaddr, parsedate
27 from email.header import decode_header
28 else:
29 from email.Utils import parseaddr, parsedate
30 from email.Header import decode_header
31
32 from datetime import datetime
33
34 try:
35 from mx.DateTime import DateTime
36 except ImportError:
37 DateTime = datetime
38
39 import logilab.common as lgc
40
41
43 parts = []
44 for decoded, charset in decode_header(string):
45 if not charset :
46 charset = 'iso-8859-15'
47 parts.append(decoded.decode(charset, 'replace'))
48
49 if sys.version_info < (3, 3):
50
51
52 return u' '.join(parts)
53 return u''.join(parts)
54
60
66
68 """Encapsulates an email.Message instance and returns only unicode objects.
69 """
70
72 self.message = message
73
74
75
76 - def get(self, header, default=None):
77 value = self.message.get(header, default)
78 if value:
79 return decode_QP(value)
80 return value
81
83 return self.get(header)
84
85 - def get_all(self, header, default=()):
86 return [decode_QP(val) for val in self.message.get_all(header, default)
87 if val is not None]
88
91
94
98
99 if sys.version_info < (3, 0):
100
102 message = self.message
103 if index is None:
104 payload = message.get_payload(index, decode)
105 if isinstance(payload, list):
106 return [UMessage(msg) for msg in payload]
107 if message.get_content_maintype() != 'text':
108 return payload
109
110 charset = message.get_content_charset() or 'iso-8859-1'
111 if search_function(charset) is None:
112 charset = 'iso-8859-1'
113 return unicode(payload or '', charset, "replace")
114 else:
115 payload = UMessage(message.get_payload(index, decode))
116 return payload
117
119 return unicode(self.message.get_content_maintype())
120
122 return unicode(self.message.get_content_type())
123
125 value = self.message.get_filename(failobj)
126 if value is failobj:
127 return value
128 try:
129 return unicode(value)
130 except UnicodeDecodeError:
131 return u'error decoding filename'
132
133 else:
134
136 message = self.message
137 if index is None:
138 payload = message.get_payload(index, decode)
139 if isinstance(payload, list):
140 return [UMessage(msg) for msg in payload]
141 return payload
142 else:
143 payload = UMessage(message.get_payload(index, decode))
144 return payload
145
147 return self.message.get_content_maintype()
148
150 return self.message.get_content_type()
151
154
155
156
158 """return an unicode string containing all the message's headers"""
159 values = []
160 for header in self.message.keys():
161 values.append(u'%s: %s' % (header, self.get(header)))
162 return '\n'.join(values)
163
165 """return a list of 2-uple (name, address) for the given address (which
166 is expected to be an header containing address such as from, to, cc...)
167 """
168 persons = []
169 for person in self.get_all(header, ()):
170 name, mail = parseaddr(person)
171 persons.append((name, mail))
172 return persons
173
174 - def date(self, alternative_source=False, return_str=False):
175 """return a datetime object for the email's date or None if no date is
176 set or if it can't be parsed
177 """
178 value = self.get('date')
179 if value is None and alternative_source:
180 unix_from = self.message.get_unixfrom()
181 if unix_from is not None:
182 try:
183 value = unix_from.split(" ", 2)[2]
184 except IndexError:
185 pass
186 if value is not None:
187 datetuple = parsedate(value)
188 if datetuple:
189 if lgc.USE_MX_DATETIME:
190 return DateTime(*datetuple[:6])
191 return datetime(*datetuple[:6])
192 elif not return_str:
193 return None
194 return value
195