1717
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
1 # The code in this module is entirely lifted from the Lamson project
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
2 # (http://lamsonproject.org/). Its copyright is:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
3
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
4 # Copyright (c) 2008, Zed A. Shaw
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
5 # All rights reserved.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
6
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
7 # It is provided under this license:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
8
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
9 # Redistribution and use in source and binary forms, with or without
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
10 # modification, are permitted provided that the following conditions are met:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
11
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
12 # * Redistributions of source code must retain the above copyright notice, this
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
13 # list of conditions and the following disclaimer.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
14
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
15 # * Redistributions in binary form must reproduce the above copyright notice,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
16 # this list of conditions and the following disclaimer in the documentation
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
17 # and/or other materials provided with the distribution.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
18
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
19 # * Neither the name of the Zed A. Shaw nor the names of its contributors may
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
20 # be used to endorse or promote products derived from this software without
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
21 # specific prior written permission.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
22
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
23 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
24 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
25 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
26 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
27 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
28 # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
29 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
30 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
31 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
32 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
33 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
34 # POSSIBILITY OF SUCH DAMAGE.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
35
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
36 import os
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
37 import mimetypes
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
38 import string
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
39 from email import encoders
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
40 from email.charset import Charset
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
41 from email.utils import parseaddr
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
42 from email.mime.base import MIMEBase
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
43
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
44 ADDRESS_HEADERS_WHITELIST = ['From', 'To', 'Delivered-To', 'Cc', 'Bcc']
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
45 DEFAULT_ENCODING = "utf-8"
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
46 VALUE_IS_EMAIL_ADDRESS = lambda v: '@' in v
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
47
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
48 def normalize_header(header):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
49 return string.capwords(header.lower(), '-')
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
50
|
1818
|
51 class EncodingError(Exception):
|
1717
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
52 """Thrown when there is an encoding error."""
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
53 pass
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
54
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
55 class MailBase(object):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
56 """MailBase is used as the basis of lamson.mail and contains the basics of
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
57 encoding an email. You actually can do all your email processing with this
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
58 class, but it's more raw.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
59 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
60 def __init__(self, items=()):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
61 self.headers = dict(items)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
62 self.parts = []
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
63 self.body = None
|
1818
|
64 self.content_encoding = {'Content-Type': (None, {}),
|
1717
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
65 'Content-Disposition': (None, {}),
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
66 'Content-Transfer-Encoding': (None, {})}
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
67
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
68 def __getitem__(self, key):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
69 return self.headers.get(normalize_header(key), None)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
70
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
71 def __len__(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
72 return len(self.headers)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
73
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
74 def __iter__(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
75 return iter(self.headers)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
76
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
77 def __contains__(self, key):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
78 return normalize_header(key) in self.headers
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
79
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
80 def __setitem__(self, key, value):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
81 self.headers[normalize_header(key)] = value
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
82
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
83 def __delitem__(self, key):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
84 del self.headers[normalize_header(key)]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
85
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
86 def __nonzero__(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
87 return self.body != None or len(self.headers) > 0 or len(self.parts) > 0
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
88
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
89 def keys(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
90 """Returns the sorted keys."""
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
91 return sorted(self.headers.keys())
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
92
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
93 def attach_file(self, filename, data, ctype, disposition):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
94 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
95 A file attachment is a raw attachment with a disposition that
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
96 indicates the file name.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
97 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
98 assert filename, "You can't attach a file without a filename."
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
99 ctype = ctype.lower()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
100
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
101 part = MailBase()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
102 part.body = data
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
103 part.content_encoding['Content-Type'] = (ctype, {'name': filename})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
104 part.content_encoding['Content-Disposition'] = (disposition,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
105 {'filename': filename})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
106 self.parts.append(part)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
107
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
108
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
109 def attach_text(self, data, ctype):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
110 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
111 This attaches a simpler text encoded part, which doesn't have a
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
112 filename.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
113 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
114 ctype = ctype.lower()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
115
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
116 part = MailBase()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
117 part.body = data
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
118 part.content_encoding['Content-Type'] = (ctype, {})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
119 self.parts.append(part)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
120
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
121 def walk(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
122 for p in self.parts:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
123 yield p
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
124 for x in p.walk():
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
125 yield x
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
126
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
127 class MailResponse(object):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
128 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
129 You are given MailResponse objects from the lamson.view methods, and
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
130 whenever you want to generate an email to send to someone. It has the
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
131 same basic functionality as MailRequest, but it is designed to be written
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
132 to, rather than read from (although you can do both).
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
133
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
134 You can easily set a Body or Html during creation or after by passing it
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
135 as __init__ parameters, or by setting those attributes.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
136
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
137 You can initially set the From, To, and Subject, but they are headers so
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
138 use the dict notation to change them: msg['From'] = 'joe@test.com'.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
139
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
140 The message is not fully crafted until right when you convert it with
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
141 MailResponse.to_message. This lets you change it and work with it, then
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
142 send it out when it's ready.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
143 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
144 def __init__(self, To=None, From=None, Subject=None, Body=None, Html=None):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
145 self.Body = Body
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
146 self.Html = Html
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
147 self.base = MailBase([('To', To), ('From', From), ('Subject', Subject)])
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
148 self.multipart = self.Body and self.Html
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
149 self.attachments = []
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
150
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
151 def __contains__(self, key):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
152 return self.base.__contains__(key)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
153
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
154 def __getitem__(self, key):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
155 return self.base.__getitem__(key)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
156
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
157 def __setitem__(self, key, val):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
158 return self.base.__setitem__(key, val)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
159
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
160 def __delitem__(self, name):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
161 del self.base[name]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
162
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
163 def attach(self, filename=None, content_type=None, data=None,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
164 disposition=None):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
165 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
166
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
167 Simplifies attaching files from disk or data as files. To attach
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
168 simple text simple give data and a content_type. To attach a file,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
169 give the data/content_type/filename/disposition combination.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
170
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
171 For convenience, if you don't give data and only a filename, then it
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
172 will read that file's contents when you call to_message() later. If
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
173 you give data and filename then it will assume you've filled data
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
174 with what the file's contents are and filename is just the name to
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
175 use.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
176 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
177
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
178 assert filename or data, ("You must give a filename or some data to "
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
179 "attach.")
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
180 assert data or os.path.exists(filename), ("File doesn't exist, and no "
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
181 "data given.")
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
182
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
183 self.multipart = True
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
184
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
185 if filename and not content_type:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
186 content_type, encoding = mimetypes.guess_type(filename)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
187
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
188 assert content_type, ("No content type given, and couldn't guess "
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
189 "from the filename: %r" % filename)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
190
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
191 self.attachments.append({'filename': filename,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
192 'content_type': content_type,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
193 'data': data,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
194 'disposition': disposition,})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
195 def attach_part(self, part):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
196 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
197 Attaches a raw MailBase part from a MailRequest (or anywhere)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
198 so that you can copy it over.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
199 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
200 self.multipart = True
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
201
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
202 self.attachments.append({'filename': None,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
203 'content_type': None,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
204 'data': None,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
205 'disposition': None,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
206 'part': part,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
207 })
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
208
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
209 def attach_all_parts(self, mail_request):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
210 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
211 Used for copying the attachment parts of a mail.MailRequest
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
212 object for mailing lists that need to maintain attachments.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
213 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
214 for part in mail_request.all_parts():
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
215 self.attach_part(part)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
216
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
217 self.base.content_encoding = mail_request.base.content_encoding.copy()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
218
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
219 def clear(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
220 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
221 Clears out the attachments so you can redo them. Use this to keep the
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
222 headers for a series of different messages with different attachments.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
223 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
224 del self.attachments[:]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
225 del self.base.parts[:]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
226 self.multipart = False
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
227
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
228
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
229 def update(self, message):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
230 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
231 Used to easily set a bunch of heading from another dict
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
232 like object.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
233 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
234 for k in message.keys():
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
235 self.base[k] = message[k]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
236
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
237 def __str__(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
238 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
239 Converts to a string.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
240 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
241 return self.to_message().as_string()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
242
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
243 def _encode_attachment(self, filename=None, content_type=None, data=None,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
244 disposition=None, part=None):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
245 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
246 Used internally to take the attachments mentioned in self.attachments
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
247 and do the actual encoding in a lazy way when you call to_message.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
248 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
249 if part:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
250 self.base.parts.append(part)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
251 elif filename:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
252 if not data:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
253 data = open(filename).read()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
254
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
255 self.base.attach_file(filename, data, content_type,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
256 disposition or 'attachment')
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
257 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
258 self.base.attach_text(data, content_type)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
259
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
260 ctype = self.base.content_encoding['Content-Type'][0]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
261
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
262 if ctype and not ctype.startswith('multipart'):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
263 self.base.content_encoding['Content-Type'] = ('multipart/mixed', {})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
264
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
265 def to_message(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
266 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
267 Figures out all the required steps to finally craft the
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
268 message you need and return it. The resulting message
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
269 is also available as a self.base attribute.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
270
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
271 What is returned is a Python email API message you can
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
272 use with those APIs. The self.base attribute is the raw
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
273 lamson.encoding.MailBase.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
274 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
275 del self.base.parts[:]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
276
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
277 if self.Body and self.Html:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
278 self.multipart = True
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
279 self.base.content_encoding['Content-Type'] = (
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
280 'multipart/alternative', {})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
281
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
282 if self.multipart:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
283 self.base.body = None
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
284 if self.Body:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
285 self.base.attach_text(self.Body, 'text/plain')
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
286
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
287 if self.Html:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
288 self.base.attach_text(self.Html, 'text/html')
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
289
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
290 for args in self.attachments:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
291 self._encode_attachment(**args)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
292
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
293 elif self.Body:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
294 self.base.body = self.Body
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
295 self.base.content_encoding['Content-Type'] = ('text/plain', {})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
296
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
297 elif self.Html:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
298 self.base.body = self.Html
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
299 self.base.content_encoding['Content-Type'] = ('text/html', {})
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
300
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
301 return to_message(self.base)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
302
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
303 def all_parts(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
304 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
305 Returns all the encoded parts. Only useful for debugging
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
306 or inspecting after calling to_message().
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
307 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
308 return self.base.parts
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
309
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
310 def keys(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
311 return self.base.keys()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
312
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
313 def to_message(mail):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
314 """
|
1818
|
315 Given a MailBase message, this will construct a MIMEPart
|
1717
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
316 that is canonicalized for use with the Python email API.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
317 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
318 ctype, params = mail.content_encoding['Content-Type']
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
319
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
320 if not ctype:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
321 if mail.parts:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
322 ctype = 'multipart/mixed'
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
323 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
324 ctype = 'text/plain'
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
325 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
326 if mail.parts:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
327 assert ctype.startswith(("multipart", "message")), \
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
328 "Content type should be multipart or message, not %r" % ctype
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
329
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
330 # adjust the content type according to what it should be now
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
331 mail.content_encoding['Content-Type'] = (ctype, params)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
332
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
333 try:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
334 out = MIMEPart(ctype, **params)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
335 except TypeError, exc: # pragma: no cover
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
336 raise EncodingError("Content-Type malformed, not allowed: %r; "
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
337 "%r (Python ERROR: %s" %
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
338 (ctype, params, exc.message))
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
339
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
340 for k in mail.keys():
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
341 if k in ADDRESS_HEADERS_WHITELIST:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
342 out[k.encode('ascii')] = header_to_mime_encoding(mail[k])
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
343 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
344 out[k.encode('ascii')] = header_to_mime_encoding(mail[k],
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
345 not_email=True)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
346
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
347 out.extract_payload(mail)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
348
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
349 # go through the children
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
350 for part in mail.parts:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
351 out.attach(to_message(part))
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
352
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
353 return out
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
354
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
355 class MIMEPart(MIMEBase):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
356 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
357 A reimplementation of nearly everything in email.mime to be more useful
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
358 for actually attaching things. Rather than one class for every type of
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
359 thing you'd encode, there's just this one, and it figures out how to
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
360 encode what you ask it.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
361 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
362 def __init__(self, type, **params):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
363 self.maintype, self.subtype = type.split('/')
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
364 MIMEBase.__init__(self, self.maintype, self.subtype, **params)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
365
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
366 def add_text(self, content):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
367 # this is text, so encode it in canonical form
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
368 try:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
369 encoded = content.encode('ascii')
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
370 charset = 'ascii'
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
371 except UnicodeError:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
372 encoded = content.encode('utf-8')
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
373 charset = 'utf-8'
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
374
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
375 self.set_payload(encoded, charset=charset)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
376
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
377
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
378 def extract_payload(self, mail):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
379 if mail.body == None: return # only None, '' is still ok
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
380
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
381 ctype, ctype_params = mail.content_encoding['Content-Type']
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
382 cdisp, cdisp_params = mail.content_encoding['Content-Disposition']
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
383
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
384 assert ctype, ("Extract payload requires that mail.content_encoding "
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
385 "have a valid Content-Type.")
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
386
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
387 if ctype.startswith("text/"):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
388 self.add_text(mail.body)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
389 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
390 if cdisp:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
391 # replicate the content-disposition settings
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
392 self.add_header('Content-Disposition', cdisp, **cdisp_params)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
393
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
394 self.set_payload(mail.body)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
395 encoders.encode_base64(self)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
396
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
397 def __repr__(self):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
398 return "<MIMEPart '%s/%s': %r, %r, multipart=%r>" % (
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
399 self.subtype,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
400 self.maintype,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
401 self['Content-Type'],
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
402 self['Content-Disposition'],
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
403 self.is_multipart())
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
404
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
405
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
406 def header_to_mime_encoding(value, not_email=False):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
407 if not value: return ""
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
408
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
409 encoder = Charset(DEFAULT_ENCODING)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
410 if type(value) == list:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
411 return "; ".join(properly_encode_header(
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
412 v, encoder, not_email) for v in value)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
413 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
414 return properly_encode_header(value, encoder, not_email)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
415
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
416 def properly_encode_header(value, encoder, not_email):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
417 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
418 The only thing special (weird) about this function is that it tries
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
419 to do a fast check to see if the header value has an email address in
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
420 it. Since random headers could have an email address, and email addresses
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
421 have weird special formatting rules, we have to check for it.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
422
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
423 Normally this works fine, but in Librelist, we need to "obfuscate" email
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
424 addresses by changing the '@' to '-AT-'. This is where
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
425 VALUE_IS_EMAIL_ADDRESS exists. It's a simple lambda returning True/False
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
426 to check if a header value has an email address. If you need to make this
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
427 check different, then change this.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
428 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
429 try:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
430 return value.encode("ascii")
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
431 except UnicodeEncodeError:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
432 if not_email is False and VALUE_IS_EMAIL_ADDRESS(value):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
433 # this could have an email address, make sure we don't screw it up
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
434 name, address = parseaddr(value)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
435 return '"%s" <%s>' % (
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
436 encoder.header_encode(name.encode("utf-8")), address)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
437
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
438 return encoder.header_encode(value.encode("utf-8"))
|