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(str(decoded, charset, 'replace'))
48
49 return ' '.join(parts)
50
56
62
64 """Encapsulates an email.Message instance and returns only unicode objects.
65 """
66
68 self.message = message
69
70
71
72 - def get(self, header, default=None):
73 value = self.message.get(header, default)
74 if value:
75 return decode_QP(value)
76 return value
77
79 return self.get(header)
80
81 - def get_all(self, header, default=()):
82 return [decode_QP(val) for val in self.message.get_all(header, default)
83 if val is not None]
84
87
90
94
95 if sys.version_info < (3, 0):
96
98 message = self.message
99 if index is None:
100 payload = message.get_payload(index, decode)
101 if isinstance(payload, list):
102 return [UMessage(msg) for msg in payload]
103 if message.get_content_maintype() != 'text':
104 return payload
105
106 charset = message.get_content_charset() or 'iso-8859-1'
107 if search_function(charset) is None:
108 charset = 'iso-8859-1'
109 return str(payload or '', charset, "replace")
110 else:
111 payload = UMessage(message.get_payload(index, decode))
112 return payload
113
115 return str(self.message.get_content_maintype())
116
118 return str(self.message.get_content_type())
119
121 value = self.message.get_filename(failobj)
122 if value is failobj:
123 return value
124 try:
125 return str(value)
126 except UnicodeDecodeError:
127 return 'error decoding filename'
128
129 else:
130
132 message = self.message
133 if index is None:
134 payload = message.get_payload(index, decode)
135 if isinstance(payload, list):
136 return [UMessage(msg) for msg in payload]
137 return payload
138 else:
139 payload = UMessage(message.get_payload(index, decode))
140 return payload
141
143 return self.message.get_content_maintype()
144
146 return self.message.get_content_type()
147
150
151
152
154 """return an unicode string containing all the message's headers"""
155 values = []
156 for header in list(self.message.keys()):
157 values.append('%s: %s' % (header, self.get(header)))
158 return '\n'.join(values)
159
161 """return a list of 2-uple (name, address) for the given address (which
162 is expected to be an header containing address such as from, to, cc...)
163 """
164 persons = []
165 for person in self.get_all(header, ()):
166 name, mail = parseaddr(person)
167 persons.append((name, mail))
168 return persons
169
170 - def date(self, alternative_source=False, return_str=False):
171 """return a datetime object for the email's date or None if no date is
172 set or if it can't be parsed
173 """
174 value = self.get('date')
175 if value is None and alternative_source:
176 unix_from = self.message.get_unixfrom()
177 if unix_from is not None:
178 try:
179 value = unix_from.split(" ", 2)[2]
180 except IndexError:
181 pass
182 if value is not None:
183 datetuple = parsedate(value)
184 if datetuple:
185 if lgc.USE_MX_DATETIME:
186 return DateTime(*datetuple[:6])
187 return datetime(*datetuple[:6])
188 elif not return_str:
189 return None
190 return value
191