v2 / vlib / net / smtp / smtp_internal_test.v
117 lines · 101 sloc · 4.78 KB · 58aba9648c741f274928fe3cf66d6aa8f146daff
Raw
1module smtp
2
3import encoding.base64
4
5fn test_mail_message_data_with_attachment_has_valid_multipart_boundaries() {
6 mail := Mail{
7 from: '[email protected]'
8 to: '[email protected]'
9 subject: 'Multipart test'
10 body: 'message body'
11 boundary: 'test-boundary'
12 attachments: [
13 Attachment{
14 filename: 'note.txt'
15 bytes: 'attachment'.bytes()
16 },
17 ]
18 }
19
20 message := mail.message_data()
21
22 assert message.contains('Content-Type: multipart/mixed; boundary="test-boundary"\r\n\r\n--test-boundary\r\n')
23 assert message.contains('Content-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\nbWVzc2FnZSBib2R5\r\n--test-boundary\r\n')
24 assert message.contains('Content-Disposition: attachment; filename="note.txt"\r\n\r\nYXR0YWNobWVudA==\r\n--test-boundary--\r\n.\r\n')
25 assert !message.contains('Content-Type: multipart/mixed; boundary="test-boundary"\r\n--test-boundary\r\n')
26 assert !message.contains('YXR0YWNobWVudA==\r\n--test-boundary\r\n.\r\n')
27}
28
29fn test_mail_message_data_with_text_and_html_uses_multipart_alternative() {
30 mail := Mail{
31 from: '[email protected]'
32 to: '[email protected]'
33 subject: 'Multipart alternative test'
34 body: 'legacy body'
35 boundary: 'test-boundary'
36 text: Message{
37 body: 'text body'
38 }
39 html: Message{
40 body: '<h1>Hello</h1>'
41 }
42 }
43
44 message := mail.message_data()
45
46 assert message.contains('MIME-Version: 1.0\r\nContent-Type: multipart/alternative; boundary="test-boundary"\r\n\r\n--test-boundary\r\n')
47 assert message.contains('Content-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\n${base64.encode_str('text body')}\r\n--test-boundary\r\n')
48 assert message.contains('Content-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\n${base64.encode_str('<h1>Hello</h1>')}\r\n--test-boundary--\r\n.\r\n')
49 assert !message.contains(base64.encode_str('legacy body'))
50 assert !message.contains('multipart/mixed')
51}
52
53fn test_mail_message_data_with_text_html_and_attachment_uses_nested_multipart() {
54 mail := Mail{
55 from: '[email protected]'
56 to: '[email protected]'
57 subject: 'Multipart mixed test'
58 boundary: 'test-boundary'
59 text: Message{
60 body: 'text body'
61 }
62 html: Message{
63 body: '<p>Hello</p>'
64 attachments: [
65 Attachment{
66 filename: 'note.txt'
67 bytes: 'attachment'.bytes()
68 },
69 ]
70 }
71 }
72
73 message := mail.message_data()
74
75 assert message.contains('Content-Type: multipart/mixed; boundary="test-boundary"\r\n\r\n--test-boundary\r\nContent-Type: multipart/alternative; boundary="test-boundary-alternative"\r\n\r\n--test-boundary-alternative\r\n')
76 assert message.contains('Content-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\n${base64.encode_str('text body')}\r\n--test-boundary-alternative\r\n')
77 assert message.contains('Content-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\n${base64.encode_str('<p>Hello</p>')}\r\n--test-boundary-alternative--\r\n')
78 assert message.contains('--test-boundary\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename="note.txt"\r\n\r\n${base64.encode_str('attachment')}\r\n--test-boundary--\r\n.\r\n')
79}
80
81fn test_fold_base64_wraps_long_lines() {
82 lines := fold_base64(base64.encode_str('0123456789'.repeat(8))).split('\r\n')
83
84 assert lines.len == 2
85 assert lines[0].len == 76
86 assert lines[1].len == 32
87}
88
89fn test_envelope_addr_strips_display_name() {
90 assert envelope_addr('[email protected]') == '[email protected]'
91 assert envelope_addr(' [email protected] ') == '[email protected]'
92 assert envelope_addr('<[email protected]>') == '[email protected]'
93 assert envelope_addr('Ivan Petrov <[email protected]>') == '[email protected]'
94 assert envelope_addr('"Petrov, Ivan" <[email protected]>') == '[email protected]'
95 // Quoted local-parts may legitimately contain '<'. Without a trailing '>',
96 // the input is not an angle-addr wrapper and must pass through unchanged.
97 assert envelope_addr('"a<b"@example.com') == '"a<b"@example.com'
98 // Quoted display name and quoted local-part both containing '<'/'>'.
99 assert envelope_addr('"a<b" <"a<b"@example.com>') == '"a<b"@example.com'
100 // Escaped quote inside a quoted display name must not end the quoted run.
101 assert envelope_addr('"a\\"<b" <[email protected]>') == '[email protected]'
102 // Malformed input (no closing '>') passes through; the server can reject.
103 assert envelope_addr('Ivan <[email protected]') == 'Ivan <[email protected]'
104}
105
106fn test_mail_message_data_preserves_display_name_in_from_header() {
107 mail := Mail{
108 from: 'Ivan Petrov <[email protected]>'
109 to: '[email protected]'
110 subject: 'Test'
111 body: 'hi'
112 }
113
114 message := mail.message_data()
115
116 assert message.contains('From: Ivan Petrov <[email protected]>\r\n')
117}
118