14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from email.Header import decode_header
19
from email.header import decode_header
20
except ImportError: # python < 3
21
from email.Header import decode_header
19
from bzrlib import __version__ as _bzrlib_version
20
from bzrlib.email_message import EmailMessage
21
from bzrlib.errors import BzrBadParameterNotUnicode
22
from bzrlib.smtp_connection import SMTPConnection
23
from bzrlib.tests import TestCase
23
from .. import __version__ as _breezy_version
24
from ..email_message import EmailMessage
25
from ..errors import BzrBadParameterNotUnicode
26
from ..sixish import text_type
27
from ..smtp_connection import SMTPConnection
25
30
EMPTY_MESSAGE = '''\
26
31
From: from@from.com
63
68
Content-Disposition: inline
66
''' % { 'version': _bzrlib_version, 'boundary': BOUNDARY }
68
SIMPLE_MULTIPART_MESSAGE = _MULTIPART_HEAD + '--%s--' % BOUNDARY
70
COMPLEX_MULTIPART_MESSAGE = _MULTIPART_HEAD + '''\
71
''' % { 'version': _breezy_version, 'boundary': BOUNDARY }
74
def final_newline_or_not(msg):
75
if sys.version_info >= (2, 7, 6):
76
# Some internals of python's email module changed in an (minor)
77
# incompatible way: a final newline is appended in 2.7.6...
82
def simple_multipart_message():
83
msg = _MULTIPART_HEAD + '--%s--' % BOUNDARY
84
return final_newline_or_not(msg)
87
def complex_multipart_message(typ):
88
msg = _MULTIPART_HEAD + '''\
73
91
Content-Type: text/%%s; charset="us-ascii"; name="lines.txt"
83
101
--%(boundary)s--''' % { 'boundary': BOUNDARY }
86
class TestEmailMessage(TestCase):
102
msg = final_newline_or_not(msg)
106
class TestEmailMessage(tests.TestCase):
88
108
def test_empty_message(self):
89
109
msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
90
self.assertEqualDiff(EMPTY_MESSAGE , msg.as_string())
110
self.assertEqualDiff(EMPTY_MESSAGE, msg.as_string())
92
112
def test_simple_message(self):
94
'body': SIMPLE_MESSAGE_ASCII,
114
b'body': SIMPLE_MESSAGE_ASCII,
95
115
u'b\xf3dy': SIMPLE_MESSAGE_UTF8,
96
'b\xc3\xb3dy': SIMPLE_MESSAGE_UTF8,
97
'b\xf4dy': SIMPLE_MESSAGE_8BIT,
116
b'b\xc3\xb3dy': SIMPLE_MESSAGE_UTF8,
117
b'b\xf4dy': SIMPLE_MESSAGE_8BIT,
99
119
for body, expected in pairs.items():
100
120
msg = EmailMessage('from@from.com', 'to@to.com', 'subject', body)
101
121
self.assertEqualDiff(expected, msg.as_string())
103
def test_multipart_message(self):
123
def test_multipart_message_simple(self):
104
124
msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
105
125
msg.add_inline_attachment('body')
106
self.assertEqualDiff(SIMPLE_MULTIPART_MESSAGE, msg.as_string(BOUNDARY))
126
self.assertEqualDiff(simple_multipart_message(),
127
msg.as_string(BOUNDARY))
130
def test_multipart_message_complex(self):
108
131
msg = EmailMessage('from@from.com', 'to@to.com', 'subject', 'body')
109
132
msg.add_inline_attachment(u'a\nb\nc\nd\ne\n', 'lines.txt', 'x-subtype')
110
self.assertEqualDiff(COMPLEX_MULTIPART_MESSAGE % 'x-subtype',
111
msg.as_string(BOUNDARY))
133
self.assertEqualDiff(complex_multipart_message('x-subtype'),
134
msg.as_string(BOUNDARY))
113
136
def test_headers_accept_unicode_and_utf8(self):
114
137
for user in [ u'Pepe P\xe9rez <pperez@ejemplo.com>',
148
171
self.assertEqual('to2@to.com', msg['To'])
149
172
self.assertEqual('cc@cc.com', msg['Cc'])
153
def get_user_option(self, option):
158
def send_as_append(_self, msg):
159
messages.append(msg.as_string(BOUNDARY))
161
old_send_email = SMTPConnection.send_email
163
SMTPConnection.send_email = send_as_append
165
EmailMessage.send(FakeConfig(), 'from@from.com', 'to@to.com',
166
'subject', 'body', u'a\nb\nc\nd\ne\n', 'lines.txt')
167
self.assertEqualDiff(COMPLEX_MULTIPART_MESSAGE % 'plain',
171
EmailMessage.send(FakeConfig(), 'from@from.com', 'to@to.com',
172
'subject', 'body', u'a\nb\nc\nd\ne\n', 'lines.txt',
174
self.assertEqualDiff(COMPLEX_MULTIPART_MESSAGE % 'x-patch',
178
EmailMessage.send(FakeConfig(), 'from@from.com', 'to@to.com',
180
self.assertEqualDiff(SIMPLE_MESSAGE_ASCII , messages[0])
183
SMTPConnection.send_email = old_send_email
185
174
def test_address_to_encoded_header(self):
187
176
"""Convert a RFC2047-encoded string to a unicode string."""
203
192
address = u'Pepe P\xe9rez <pperez@ejemplo.com>' # unicode ok
204
193
encoded = EmailMessage.address_to_encoded_header(address)
205
self.assert_('pperez@ejemplo.com' in encoded) # addr must be unencoded
206
self.assertEquals(address, decode(encoded))
194
self.assertTrue('pperez@ejemplo.com' in encoded) # addr must be unencoded
195
self.assertEqual(address, decode(encoded))
208
197
address = 'Pepe P\xc3\xa9red <pperez@ejemplo.com>' # UTF-8 ok
209
198
encoded = EmailMessage.address_to_encoded_header(address)
210
self.assert_('pperez@ejemplo.com' in encoded)
211
self.assertEquals(address, decode(encoded).encode('utf-8'))
199
self.assertTrue('pperez@ejemplo.com' in encoded)
200
self.assertEqual(address, decode(encoded).encode('utf-8'))
213
202
address = 'Pepe P\xe9rez <pperez@ejemplo.com>' # ISO-8859-1 not ok
214
203
self.assertRaises(BzrBadParameterNotUnicode,
217
206
def test_string_with_encoding(self):
219
u'Pepe': ('Pepe', 'ascii'),
220
u'P\xe9rez': ('P\xc3\xa9rez', 'utf-8'),
221
'Perez': ('Perez', 'ascii'), # u'Pepe' == 'Pepe'
222
'P\xc3\xa9rez': ('P\xc3\xa9rez', 'utf-8'),
223
'P\xe8rez': ('P\xe8rez', '8-bit'),
208
u'Pepe': (b'Pepe', 'ascii'),
209
u'P\xe9rez': (b'P\xc3\xa9rez', 'utf-8'),
210
b'Perez': (b'Perez', 'ascii'), # u'Pepe' == 'Pepe'
211
b'P\xc3\xa9rez': (b'P\xc3\xa9rez', 'utf-8'),
212
b'P\xe8rez': (b'P\xe8rez', '8-bit'),
225
214
for string_, pair in pairs.items():
226
215
self.assertEqual(pair, EmailMessage.string_with_encoding(string_))
218
class TestSend(tests.TestCase):
221
super(TestSend, self).setUp()
224
def send_as_append(_self, msg):
225
self.messages.append(msg.as_string(BOUNDARY))
227
self.overrideAttr(SMTPConnection, 'send_email', send_as_append)
231
def send_email(self, attachment=None, attachment_filename=None,
232
attachment_mime_subtype='plain'):
234
def get(self, option):
237
EmailMessage.send(FakeConfig(), 'from@from.com', 'to@to.com',
239
attachment=attachment,
240
attachment_filename=attachment_filename,
241
attachment_mime_subtype=attachment_mime_subtype)
243
def assertMessage(self, expected):
244
self.assertLength(1, self.messages)
245
self.assertEqualDiff(expected, self.messages[0])
247
def test_send_plain(self):
248
self.send_email(u'a\nb\nc\nd\ne\n', 'lines.txt')
249
self.assertMessage(complex_multipart_message('plain'))
251
def test_send_patch(self):
252
self.send_email(u'a\nb\nc\nd\ne\n', 'lines.txt', 'x-patch')
253
self.assertMessage(complex_multipart_message('x-patch'))
255
def test_send_simple(self):
257
self.assertMessage(SIMPLE_MESSAGE_ASCII)