blob: 17ae02493578c25d8bd29be86cb05e550faf5510 [file] [log] [blame]
Dusan Kasanc2129de2017-04-13 10:42:21 +02001package parsemail
Dusan Kasan17e497e2017-04-10 22:44:22 +02002
3import (
Dusan Kasan17e497e2017-04-10 22:44:22 +02004 "encoding/base64"
5 "io/ioutil"
Dusan Kasan4595dfe2017-04-13 00:38:24 +02006 "net/mail"
7 "strings"
8 "testing"
9 "time"
Dusan Kasan17e497e2017-04-10 22:44:22 +020010)
11
12func TestParseEmail(t *testing.T) {
Dusan Kasan4595dfe2017-04-13 00:38:24 +020013 var testData = map[int]struct {
Dusan Kasan17e497e2017-04-10 22:44:22 +020014 mailData string
15
Dusan Kasan428369f2020-02-24 00:47:31 +010016 contentType string
17 content string
Dusan Kasan4595dfe2017-04-13 00:38:24 +020018 subject string
19 date time.Time
20 from []mail.Address
21 sender mail.Address
22 to []mail.Address
23 replyTo []mail.Address
24 cc []mail.Address
25 bcc []mail.Address
26 messageID string
27 resentDate time.Time
28 resentFrom []mail.Address
29 resentSender mail.Address
30 resentTo []mail.Address
31 resentReplyTo []mail.Address
32 resentCc []mail.Address
33 resentBcc []mail.Address
Dusan Kasanb49ceb62017-04-13 00:00:36 +020034 resentMessageID string
Dusan Kasan4595dfe2017-04-13 00:38:24 +020035 inReplyTo []string
36 references []string
37 htmlBody string
38 textBody string
39 attachments []attachmentData
40 embeddedFiles []embeddedFileData
41 headerCheck func(mail.Header, *testing.T)
Dusan Kasan17e497e2017-04-10 22:44:22 +020042 }{
Dusan Kasanb49ceb62017-04-13 00:00:36 +020043 1: {
Dusan Kasan45ca2642017-04-18 10:39:35 +020044 mailData: rfc5322exampleA11,
Dusan Kasan4595dfe2017-04-13 00:38:24 +020045 subject: "Saying Hello",
Dusan Kasanb49ceb62017-04-13 00:00:36 +020046 from: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +020047 {
48 Name: "John Doe",
49 Address: "jdoe@machine.example",
50 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +020051 },
52 to: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +020053 {
54 Name: "Mary Smith",
55 Address: "mary@example.net",
56 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +020057 },
Dusan Kasan45ca2642017-04-18 10:39:35 +020058 sender: mail.Address{
59 Name: "Michael Jones",
60 Address: "mjones@machine.example",
61 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +020062 messageID: "1234@local.machine.example",
Dusan Kasan4595dfe2017-04-13 00:38:24 +020063 date: parseDate("Fri, 21 Nov 1997 09:55:06 -0600"),
Dusan Kasanb49ceb62017-04-13 00:00:36 +020064 textBody: `This is a message just to say hello.
65So, "Hello".`,
66 },
67 2: {
Dusan Kasan45ca2642017-04-18 10:39:35 +020068 mailData: rfc5322exampleA12,
Dusan Kasanb49ceb62017-04-13 00:00:36 +020069 from: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +020070 {
71 Name: "Joe Q. Public",
72 Address: "john.q.public@example.com",
73 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +020074 },
75 to: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +020076 {
77 Name: "Mary Smith",
78 Address: "mary@x.test",
79 },
80 {
81 Name: "",
82 Address: "jdoe@example.org",
83 },
84 {
85 Name: "Who?",
86 Address: "one@y.test",
87 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +020088 },
89 cc: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +020090 {
91 Name: "",
92 Address: "boss@nil.test",
93 },
94 {
95 Name: "Giant; \"Big\" Box",
96 Address: "sysservices@example.net",
97 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +020098 },
99 messageID: "5678.21-Nov-1997@example.com",
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200100 date: parseDate("Tue, 01 Jul 2003 10:52:37 +0200"),
101 textBody: `Hi everyone.`,
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200102 },
103 3: {
Dusan Kasan45ca2642017-04-18 10:39:35 +0200104 mailData: rfc5322exampleA2a,
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200105 subject: "Re: Saying Hello",
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200106 from: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200107 {
108 Name: "Mary Smith",
109 Address: "mary@example.net",
110 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200111 },
112 replyTo: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200113 {
114 Name: "Mary Smith: Personal Account",
115 Address: "smith@home.example",
116 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200117 },
118 to: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200119 {
120 Name: "John Doe",
121 Address: "jdoe@machine.example",
122 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200123 },
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200124 messageID: "3456@example.net",
125 inReplyTo: []string{"1234@local.machine.example"},
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200126 references: []string{"1234@local.machine.example"},
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200127 date: parseDate("Fri, 21 Nov 1997 10:01:10 -0600"),
128 textBody: `This is a reply to your hello.`,
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200129 },
130 4: {
Dusan Kasan45ca2642017-04-18 10:39:35 +0200131 mailData: rfc5322exampleA2b,
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200132 subject: "Re: Saying Hello",
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200133 from: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200134 {
135 Name: "John Doe",
136 Address: "jdoe@machine.example",
137 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200138 },
139 to: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200140 {
141 Name: "Mary Smith: Personal Account",
142 Address: "smith@home.example",
143 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200144 },
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200145 messageID: "abcd.1234@local.machine.test",
146 inReplyTo: []string{"3456@example.net"},
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200147 references: []string{"1234@local.machine.example", "3456@example.net"},
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200148 date: parseDate("Fri, 21 Nov 1997 11:00:00 -0600"),
149 textBody: `This is a reply to your reply.`,
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200150 },
151 5: {
Dusan Kasan45ca2642017-04-18 10:39:35 +0200152 mailData: rfc5322exampleA3,
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200153 subject: "Saying Hello",
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200154 from: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200155 {
156 Name: "John Doe",
157 Address: "jdoe@machine.example",
158 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200159 },
160 to: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200161 {
162 Name: "Mary Smith",
163 Address: "mary@example.net",
164 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200165 },
166 messageID: "1234@local.machine.example",
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200167 date: parseDate("Fri, 21 Nov 1997 09:55:06 -0600"),
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200168 resentFrom: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200169 {
170 Name: "Mary Smith",
171 Address: "mary@example.net",
172 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200173 },
174 resentTo: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200175 {
176 Name: "Jane Brown",
177 Address: "j-brown@other.example",
178 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200179 },
180 resentMessageID: "78910@example.net",
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200181 resentDate: parseDate("Mon, 24 Nov 1997 14:22:01 -0800"),
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200182 textBody: `This is a message just to say hello.
183So, "Hello".`,
184 },
185 6: {
Dusan Kasan45ca2642017-04-18 10:39:35 +0200186 mailData: data1,
Dusan Kasan428369f2020-02-24 00:47:31 +0100187 contentType: `multipart/mixed; boundary=f403045f1dcc043a44054c8e6bbf`,
188 content: "",
Dusan Kasanf4376a62017-05-23 21:03:55 +0200189 subject: "Peter Paholík",
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200190 from: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200191 {
192 Name: "Peter Paholík",
193 Address: "peter.paholik@gmail.com",
194 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200195 },
196 to: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200197 {
198 Name: "",
199 Address: "dusan@kasan.sk",
200 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200201 },
Dusan Kasan17e497e2017-04-10 22:44:22 +0200202 messageID: "CACtgX4kNXE7T5XKSKeH_zEcfUUmf2vXVASxYjaaK9cCn-3zb_g@mail.gmail.com",
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200203 date: parseDate("Fri, 07 Apr 2017 09:17:26 +0200"),
204 htmlBody: "<div dir=\"ltr\"><br></div>",
Dusan Kasan17e497e2017-04-10 22:44:22 +0200205 attachments: []attachmentData{
206 {
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200207 filename: "Peter Paholík 1 4 2017 2017-04-07.pdf",
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200208 contentType: "application/pdf",
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200209 base64data: "JVBERi0xLjQNCiW1tbW1DQoxIDAgb2JqDQo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFIvTGFuZyhlbi1VUykgL1N0cnVjdFRyZWVSb290IDY3IDAgUi9NYXJrSW5mbzw8L01hcmtlZCB0cnVlPj4vT3V0cHV0SW50ZW50c1s8PC9UeXBlL091dHB1dEludGVudC9TL0dUU19QREZBMS9PdXRwdXRDb25kZXYgMzk1MzYyDQo+Pg0Kc3RhcnR4cmVmDQo0MTk4ODUNCiUlRU9GDQo=",
Dusan Kasan17e497e2017-04-10 22:44:22 +0200210 },
211 },
212 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200213 7: {
Dusan Kasan45ca2642017-04-18 10:39:35 +0200214 mailData: data2,
Dusan Kasan428369f2020-02-24 00:47:31 +0100215 contentType: `multipart/alternative; boundary="------------C70C0458A558E585ACB75FB4"`,
216 content: "",
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200217 subject: "Re: Test Subject 2",
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200218 from: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200219 {
220 Name: "Sender Man",
221 Address: "sender@domain.com",
222 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200223 },
224 to: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200225 {
226 Name: "",
227 Address: "info@receiver.com",
228 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200229 },
230 cc: []mail.Address{
Dusan Kasan45ca2642017-04-18 10:39:35 +0200231 {
232 Name: "Cc Man",
233 Address: "ccman@gmail.com",
234 },
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200235 },
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200236 messageID: "0e9a21b4-01dc-e5c1-dcd6-58ce5aa61f4f@receiver.com",
237 inReplyTo: []string{"9ff38d03-c4ab-89b7-9328-e99d5e24e3ba@receiver.eu"},
Dusan Kasan17e497e2017-04-10 22:44:22 +0200238 references: []string{"2f6b7595-c01e-46e5-42bc-f263e1c4282d@receiver.com", "9ff38d03-c4ab-89b7-9328-e99d5e24e3ba@domain.com"},
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200239 date: parseDate("Fri, 07 Apr 2017 12:59:55 +0200"),
240 htmlBody: `<html>data<img src="part2.9599C449.04E5EC81@develhell.com"/></html>`,
Dusan Kasan17e497e2017-04-10 22:44:22 +0200241 textBody: `First level
242> Second level
243>> Third level
244>
245`,
246 embeddedFiles: []embeddedFileData{
247 {
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200248 cid: "part2.9599C449.04E5EC81@develhell.com",
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200249 contentType: "image/png",
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200250 base64data: "iVBORw0KGgoAAAANSUhEUgAAAQEAAAAYCAIAAAB1IN9NAAAACXBIWXMAAAsTAAALEwEAmpwYYKUKF+Os3baUndC0pDnwNAmLy1SUr2Gw0luxQuV/AwC6cEhVV5VRrwAAAABJRU5ErkJggg==",
Dusan Kasan17e497e2017-04-10 22:44:22 +0200251 },
252 },
253 },
Dusan Kasan428369f2020-02-24 00:47:31 +0100254 8: {
255 mailData: imageContentExample,
256 subject: "Saying Hello",
257 from: []mail.Address{
258 {
259 Name: "John Doe",
260 Address: "jdoe@machine.example",
261 },
262 },
263 to: []mail.Address{
264 {
265 Name: "Mary Smith",
266 Address: "mary@example.net",
267 },
268 },
269 sender: mail.Address{
270 Name: "Michael Jones",
271 Address: "mjones@machine.example",
272 },
273 messageID: "1234@local.machine.example",
274 date: parseDate("Fri, 21 Nov 1997 09:55:06 -0600"),
275 contentType: `image/jpeg; x-unix-mode=0644; name="image.gif"`,
276 content: `GIF89a;`,
277 },
Dusan Kasane97c2f22020-04-04 10:50:00 +0200278 9: {
279 contentType: `multipart/mixed; boundary="0000000000007e2bb40587e36196"`,
280 mailData: textPlainInMultipart,
Maya Rashishbae116e2019-06-10 12:15:25 +0300281 subject: "Re: kern/54143 (virtualbox)",
282 from: []mail.Address{
283 {
284 Name: "Rares",
285 Address: "rares@example.com",
286 },
287 },
288 to: []mail.Address{
289 {
290 Name: "",
291 Address: "bugs@example.com",
292 },
293 },
294 date: parseDate("Fri, 02 May 2019 11:25:35 +0300"),
295 textBody: `plain text part`,
296 },
Dusan Kasan88226cf2020-04-04 11:13:06 +0200297 10: {
298 mailData: rfc5322exampleA12WithTimezone,
299 from: []mail.Address{
300 {
301 Name: "Joe Q. Public",
302 Address: "john.q.public@example.com",
303 },
304 },
305 to: []mail.Address{
306 {
307 Name: "Mary Smith",
308 Address: "mary@x.test",
309 },
310 {
311 Name: "",
312 Address: "jdoe@example.org",
313 },
314 {
315 Name: "Who?",
316 Address: "one@y.test",
317 },
318 },
319 cc: []mail.Address{
320 {
321 Name: "",
322 Address: "boss@nil.test",
323 },
324 {
325 Name: "Giant; \"Big\" Box",
326 Address: "sysservices@example.net",
327 },
328 },
329 messageID: "5678.21-Nov-1997@example.com",
330 date: parseDate("Tue, 01 Jul 2003 10:52:37 +0200"),
331 textBody: `Hi everyone.`,
332 },
Dusan Kasan17e497e2017-04-10 22:44:22 +0200333 }
334
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200335 for index, td := range testData {
Dusan Kasan428369f2020-02-24 00:47:31 +0100336 e, err := Parse(strings.NewReader(td.mailData))
Antonio331b1182019-01-15 09:58:52 +0100337 if err != nil {
338 t.Error(err)
339 }
Dusan Kasan428369f2020-02-24 00:47:31 +0100340
341 if td.contentType != e.ContentType {
342 t.Errorf("[Test Case %v] Wrong content type. Expected: %s, Got: %s", index, td.contentType, e.ContentType)
343 }
344
345 if td.content != "" {
346 b, err := ioutil.ReadAll(e.Content)
347 if err != nil {
348 t.Error(err)
349 } else if td.content != string(b) {
350 t.Errorf("[Test Case %v] Wrong content. Expected: %s, Got: %s", index, td.content, string(b))
351 }
Dusan Kasan17e497e2017-04-10 22:44:22 +0200352 }
353
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200354 if td.subject != e.Subject {
355 t.Errorf("[Test Case %v] Wrong subject. Expected: %s, Got: %s", index, td.subject, e.Subject)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200356 }
357
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200358 if td.messageID != e.MessageID {
359 t.Errorf("[Test Case %v] Wrong messageID. Expected: '%s', Got: '%s'", index, td.messageID, e.MessageID)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200360 }
361
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200362 if !td.date.Equal(e.Date) {
363 t.Errorf("[Test Case %v] Wrong date. Expected: %v, Got: %v", index, td.date, e.Date)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200364 }
365
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200366 d := dereferenceAddressList(e.From)
367 if !assertAddressListEq(td.from, d) {
368 t.Errorf("[Test Case %v] Wrong from. Expected: %s, Got: %s", index, td.from, d)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200369 }
370
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200371 var sender mail.Address
372 if e.Sender != nil {
373 sender = *e.Sender
374 }
375 if td.sender != sender {
376 t.Errorf("[Test Case %v] Wrong sender. Expected: %s, Got: %s", index, td.sender, sender)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200377 }
378
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200379 d = dereferenceAddressList(e.To)
380 if !assertAddressListEq(td.to, d) {
381 t.Errorf("[Test Case %v] Wrong to. Expected: %s, Got: %s", index, td.to, d)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200382 }
383
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200384 d = dereferenceAddressList(e.Cc)
385 if !assertAddressListEq(td.cc, d) {
386 t.Errorf("[Test Case %v] Wrong cc. Expected: %s, Got: %s", index, td.cc, d)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200387 }
388
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200389 d = dereferenceAddressList(e.Bcc)
390 if !assertAddressListEq(td.bcc, d) {
391 t.Errorf("[Test Case %v] Wrong bcc. Expected: %s, Got: %s", index, td.bcc, d)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200392 }
393
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200394 if td.resentMessageID != e.ResentMessageID {
395 t.Errorf("[Test Case %v] Wrong resent messageID. Expected: '%s', Got: '%s'", index, td.resentMessageID, e.ResentMessageID)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200396 }
397
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200398 if !td.resentDate.Equal(e.ResentDate) && !td.resentDate.IsZero() && !e.ResentDate.IsZero() {
399 t.Errorf("[Test Case %v] Wrong resent date. Expected: %v, Got: %v", index, td.resentDate, e.ResentDate)
400 }
401
402 d = dereferenceAddressList(e.ResentFrom)
403 if !assertAddressListEq(td.resentFrom, d) {
404 t.Errorf("[Test Case %v] Wrong resent from. Expected: %s, Got: %s", index, td.resentFrom, d)
405 }
406
407 var resentSender mail.Address
408 if e.ResentSender != nil {
409 resentSender = *e.ResentSender
410 }
411 if td.resentSender != resentSender {
412 t.Errorf("[Test Case %v] Wrong resent sender. Expected: %s, Got: %s", index, td.resentSender, resentSender)
413 }
414
415 d = dereferenceAddressList(e.ResentTo)
416 if !assertAddressListEq(td.resentTo, d) {
417 t.Errorf("[Test Case %v] Wrong resent to. Expected: %s, Got: %s", index, td.resentTo, d)
418 }
419
420 d = dereferenceAddressList(e.ResentCc)
421 if !assertAddressListEq(td.resentCc, d) {
422 t.Errorf("[Test Case %v] Wrong resent cc. Expected: %s, Got: %s", index, td.resentCc, d)
423 }
424
425 d = dereferenceAddressList(e.ResentBcc)
426 if !assertAddressListEq(td.resentBcc, d) {
427 t.Errorf("[Test Case %v] Wrong resent bcc. Expected: %s, Got: %s", index, td.resentBcc, d)
428 }
429
430 if !assertSliceEq(td.inReplyTo, e.InReplyTo) {
431 t.Errorf("[Test Case %v] Wrong in reply to. Expected: %s, Got: %s", index, td.inReplyTo, e.InReplyTo)
432 }
433
434 if !assertSliceEq(td.references, e.References) {
435 t.Errorf("[Test Case %v] Wrong references. Expected: %s, Got: %s", index, td.references, e.References)
436 }
437
438 d = dereferenceAddressList(e.ReplyTo)
439 if !assertAddressListEq(td.replyTo, d) {
440 t.Errorf("[Test Case %v] Wrong reply to. Expected: %s, Got: %s", index, td.replyTo, d)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200441 }
442
443 if td.htmlBody != e.HTMLBody {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200444 t.Errorf("[Test Case %v] Wrong html body. Expected: '%s', Got: '%s'", index, td.htmlBody, e.HTMLBody)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200445 }
446
447 if td.textBody != e.TextBody {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200448 t.Errorf("[Test Case %v] Wrong text body. Expected: '%s', Got: '%s'", index, td.textBody, e.TextBody)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200449 }
450
Dusan Kasan17e497e2017-04-10 22:44:22 +0200451 if len(td.attachments) != len(e.Attachments) {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200452 t.Errorf("[Test Case %v] Incorrect number of attachments! Expected: %v, Got: %v.", index, len(td.attachments), len(e.Attachments))
Dusan Kasan17e497e2017-04-10 22:44:22 +0200453 } else {
454 attachs := e.Attachments[:]
455
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200456 for _, ad := range td.attachments {
Dusan Kasan17e497e2017-04-10 22:44:22 +0200457 found := false
458
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200459 for i, ra := range attachs {
Dusan Kasan17e497e2017-04-10 22:44:22 +0200460 b, err := ioutil.ReadAll(ra.Data)
461 if err != nil {
462 t.Error(err)
463 }
464
465 encoded := base64.StdEncoding.EncodeToString(b)
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200466 if ra.Filename == ad.filename && encoded == ad.base64data && ra.ContentType == ad.contentType {
Dusan Kasan17e497e2017-04-10 22:44:22 +0200467 found = true
468 attachs = append(attachs[:i], attachs[i+1:]...)
469 }
470 }
471
472 if !found {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200473 t.Errorf("[Test Case %v] Attachment not found: %s", index, ad.filename)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200474 }
475 }
476
477 if len(attachs) != 0 {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200478 t.Errorf("[Test Case %v] Email contains %v unexpected attachments: %v", index, len(attachs), attachs)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200479 }
480 }
481
482 if len(td.embeddedFiles) != len(e.EmbeddedFiles) {
Dusan Kasan1a966482017-04-18 10:45:25 +0200483 t.Errorf("[Test Case %v] Incorrect number of embedded files! Expected: %v, Got: %v.", index, len(td.embeddedFiles), len(e.EmbeddedFiles))
Dusan Kasan17e497e2017-04-10 22:44:22 +0200484 } else {
485 embeds := e.EmbeddedFiles[:]
486
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200487 for _, ad := range td.embeddedFiles {
Dusan Kasan17e497e2017-04-10 22:44:22 +0200488 found := false
489
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200490 for i, ra := range embeds {
Dusan Kasan17e497e2017-04-10 22:44:22 +0200491 b, err := ioutil.ReadAll(ra.Data)
492 if err != nil {
493 t.Error(err)
494 }
495
496 encoded := base64.StdEncoding.EncodeToString(b)
497
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200498 if ra.CID == ad.cid && encoded == ad.base64data && ra.ContentType == ad.contentType {
Dusan Kasan17e497e2017-04-10 22:44:22 +0200499 found = true
500 embeds = append(embeds[:i], embeds[i+1:]...)
501 }
502 }
503
504 if !found {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200505 t.Errorf("[Test Case %v] Embedded file not found: %s", index, ad.cid)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200506 }
507 }
508
509 if len(embeds) != 0 {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200510 t.Errorf("[Test Case %v] Email contains %v unexpected embedded files: %v", index, len(embeds), embeds)
Dusan Kasan17e497e2017-04-10 22:44:22 +0200511 }
512 }
513 }
514}
515
516func parseDate(in string) time.Time {
517 out, err := time.Parse(time.RFC1123Z, in)
518 if err != nil {
519 panic(err)
520 }
521
522 return out
523}
524
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200525type attachmentData struct {
526 filename string
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200527 contentType string
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200528 base64data string
Dusan Kasan17e497e2017-04-10 22:44:22 +0200529}
530
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200531type embeddedFileData struct {
532 cid string
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200533 contentType string
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200534 base64data string
Dusan Kasan17e497e2017-04-10 22:44:22 +0200535}
536
537func assertSliceEq(a, b []string) bool {
538 if len(a) == len(b) && len(a) == 0 {
539 return true
540 }
541
542 if a == nil && b == nil {
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200543 return true
Dusan Kasan17e497e2017-04-10 22:44:22 +0200544 }
545
546 if a == nil || b == nil {
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200547 return false
Dusan Kasan17e497e2017-04-10 22:44:22 +0200548 }
549
550 if len(a) != len(b) {
551 return false
552 }
553
554 for i := range a {
555 if a[i] != b[i] {
556 return false
557 }
558 }
559
560 return true
561}
562
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200563func assertAddressListEq(a, b []mail.Address) bool {
564 if len(a) == len(b) && len(a) == 0 {
565 return true
566 }
567
568 if a == nil && b == nil {
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200569 return true
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200570 }
571
572 if a == nil || b == nil {
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200573 return false
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200574 }
575
576 if len(a) != len(b) {
577 return false
578 }
579
580 for i := range a {
581 if a[i] != b[i] {
582 return false
583 }
584 }
585
586 return true
587}
588
589func dereferenceAddressList(al []*mail.Address) (result []mail.Address) {
Dusan Kasan4595dfe2017-04-13 00:38:24 +0200590 for _, a := range al {
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200591 result = append(result, *a)
592 }
593
594 return
595}
596
Dusan Kasan45ca2642017-04-18 10:39:35 +0200597var data1 = `From: =?UTF-8?Q?Peter_Pahol=C3=ADk?= <peter.paholik@gmail.com>
Dusan Kasan17e497e2017-04-10 22:44:22 +0200598Date: Fri, 7 Apr 2017 09:17:26 +0200
599Message-ID: <CACtgX4kNXE7T5XKSKeH_zEcfUUmf2vXVASxYjaaK9cCn-3zb_g@mail.gmail.com>
Dusan Kasanf4376a62017-05-23 21:03:55 +0200600Subject: =?UTF-8?Q?Peter_Pahol=C3=ADk?=
Dusan Kasan17e497e2017-04-10 22:44:22 +0200601To: dusan@kasan.sk
602Content-Type: multipart/mixed; boundary=f403045f1dcc043a44054c8e6bbf
603
604--f403045f1dcc043a44054c8e6bbf
605Content-Type: multipart/alternative; boundary=f403045f1dcc043a3f054c8e6bbd
606
607--f403045f1dcc043a3f054c8e6bbd
608Content-Type: text/plain; charset=UTF-8
609
610
611
612--f403045f1dcc043a3f054c8e6bbd
613Content-Type: text/html; charset=UTF-8
614
615<div dir="ltr"><br></div>
616
617--f403045f1dcc043a3f054c8e6bbd--
618--f403045f1dcc043a44054c8e6bbf
619Content-Type: application/pdf;
620 name="=?UTF-8?Q?Peter_Paholi=CC=81k_1?=
621 =?UTF-8?Q?_4_2017_2017=2D04=2D07=2Epdf?="
622Content-Disposition: attachment;
623 filename="=?UTF-8?Q?Peter_Paholi=CC=81k_1?=
624 =?UTF-8?Q?_4_2017_2017=2D04=2D07=2Epdf?="
625Content-Transfer-Encoding: base64
626X-Attachment-Id: f_j17i0f0d0
627
628JVBERi0xLjQNCiW1tbW1DQoxIDAgb2JqDQo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFIvTGFu
629Zyhlbi1VUykgL1N0cnVjdFRyZWVSb290IDY3IDAgUi9NYXJrSW5mbzw8L01hcmtlZCB0cnVlPj4v
630T3V0cHV0SW50ZW50c1s8PC9UeXBlL091dHB1dEludGVudC9TL0dUU19QREZBMS9PdXRwdXRDb25k
631ZXYgMzk1MzYyDQo+Pg0Kc3RhcnR4cmVmDQo0MTk4ODUNCiUlRU9GDQo=
632--f403045f1dcc043a44054c8e6bbf--
633`
634
Dusan Kasan45ca2642017-04-18 10:39:35 +0200635var data2 = `Subject: Re: Test Subject 2
Dusan Kasan17e497e2017-04-10 22:44:22 +0200636To: info@receiver.com
637References: <2f6b7595-c01e-46e5-42bc-f263e1c4282d@receiver.com>
638 <9ff38d03-c4ab-89b7-9328-e99d5e24e3ba@domain.com>
639Cc: Cc Man <ccman@gmail.com>
640From: Sender Man <sender@domain.com>
641Message-ID: <0e9a21b4-01dc-e5c1-dcd6-58ce5aa61f4f@receiver.com>
642Date: Fri, 7 Apr 2017 12:59:55 +0200
643User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:45.0)
644 Gecko/20100101 Thunderbird/45.8.0
645MIME-Version: 1.0
646In-Reply-To: <9ff38d03-c4ab-89b7-9328-e99d5e24e3ba@receiver.eu>
647Content-Type: multipart/alternative;
648 boundary="------------C70C0458A558E585ACB75FB4"
649
650This is a multi-part message in MIME format.
651--------------C70C0458A558E585ACB75FB4
652Content-Type: text/plain; charset=utf-8; format=flowed
653Content-Transfer-Encoding: 8bit
654
655First level
656> Second level
657>> Third level
658>
659
660
661--------------C70C0458A558E585ACB75FB4
662Content-Type: multipart/related;
663 boundary="------------5DB4A1356834BB602A5F88B2"
664
665
666--------------5DB4A1356834BB602A5F88B2
667Content-Type: text/html; charset=utf-8
668Content-Transfer-Encoding: 8bit
669
670<html>data<img src="part2.9599C449.04E5EC81@develhell.com"/></html>
671
672--------------5DB4A1356834BB602A5F88B2
673Content-Type: image/png
674Content-Transfer-Encoding: base64
675Content-ID: <part2.9599C449.04E5EC81@develhell.com>
676
677iVBORw0KGgoAAAANSUhEUgAAAQEAAAAYCAIAAAB1IN9NAAAACXBIWXMAAAsTAAALEwEAmpwY
678YKUKF+Os3baUndC0pDnwNAmLy1SUr2Gw0luxQuV/AwC6cEhVV5VRrwAAAABJRU5ErkJggg==
679--------------5DB4A1356834BB602A5F88B2
680
681--------------C70C0458A558E585ACB75FB4--
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200682`
683
Dusan Kasane97c2f22020-04-04 10:50:00 +0200684var textPlainInMultipart = `From: Rares <rares@example.com>
Maya Rashishbae116e2019-06-10 12:15:25 +0300685Date: Thu, 2 May 2019 11:25:35 +0300
686Subject: Re: kern/54143 (virtualbox)
687To: bugs@example.com
688Content-Type: multipart/mixed; boundary="0000000000007e2bb40587e36196"
689
690--0000000000007e2bb40587e36196
691Content-Type: text/plain; charset="UTF-8"
692
693plain text part
694--0000000000007e2bb40587e36196--
695`
696
Dusan Kasan45ca2642017-04-18 10:39:35 +0200697var rfc5322exampleA11 = `From: John Doe <jdoe@machine.example>
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200698Sender: Michael Jones <mjones@machine.example>
699To: Mary Smith <mary@example.net>
700Subject: Saying Hello
701Date: Fri, 21 Nov 1997 09:55:06 -0600
702Message-ID: <1234@local.machine.example>
703
704This is a message just to say hello.
705So, "Hello".
706`
707
Dusan Kasan45ca2642017-04-18 10:39:35 +0200708var rfc5322exampleA12 = `From: "Joe Q. Public" <john.q.public@example.com>
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200709To: Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>
710Cc: <boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>
711Date: Tue, 1 Jul 2003 10:52:37 +0200
712Message-ID: <5678.21-Nov-1997@example.com>
713
714Hi everyone.
715`
716
Dusan Kasan88226cf2020-04-04 11:13:06 +0200717var rfc5322exampleA12WithTimezone = `From: "Joe Q. Public" <john.q.public@example.com>
718To: Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>
719Cc: <boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>
Edwin Love33953e52019-04-02 15:29:22 +0100720Date: Tue, 1 Jul 2003 10:52:37 +0200 (GMT)
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200721Message-ID: <5678.21-Nov-1997@example.com>
722
723Hi everyone.
724`
725
Dusan Kasan88226cf2020-04-04 11:13:06 +0200726
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200727//todo: not yet implemented in net/mail
728//once there is support for this, add it
Dusan Kasan45ca2642017-04-18 10:39:35 +0200729var rfc5322exampleA13 = `From: Pete <pete@silly.example>
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200730To: A Group:Ed Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;
731Cc: Undisclosed recipients:;
732Date: Thu, 13 Feb 1969 23:32:54 -0330
733Message-ID: <testabcd.1234@silly.example>
734
735Testing.
736`
737
738//we skipped the first message bcause it's the same as A 1.1
Dusan Kasan45ca2642017-04-18 10:39:35 +0200739var rfc5322exampleA2a = `From: Mary Smith <mary@example.net>
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200740To: John Doe <jdoe@machine.example>
741Reply-To: "Mary Smith: Personal Account" <smith@home.example>
742Subject: Re: Saying Hello
743Date: Fri, 21 Nov 1997 10:01:10 -0600
744Message-ID: <3456@example.net>
745In-Reply-To: <1234@local.machine.example>
746References: <1234@local.machine.example>
747
748This is a reply to your hello.
749`
750
Dusan Kasan45ca2642017-04-18 10:39:35 +0200751var rfc5322exampleA2b = `To: "Mary Smith: Personal Account" <smith@home.example>
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200752From: John Doe <jdoe@machine.example>
753Subject: Re: Saying Hello
754Date: Fri, 21 Nov 1997 11:00:00 -0600
755Message-ID: <abcd.1234@local.machine.test>
756In-Reply-To: <3456@example.net>
757References: <1234@local.machine.example> <3456@example.net>
758
759This is a reply to your reply.
760`
761
Dusan Kasan45ca2642017-04-18 10:39:35 +0200762var rfc5322exampleA3 = `Resent-From: Mary Smith <mary@example.net>
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200763Resent-To: Jane Brown <j-brown@other.example>
764Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800
765Resent-Message-ID: <78910@example.net>
766From: John Doe <jdoe@machine.example>
767To: Mary Smith <mary@example.net>
768Subject: Saying Hello
769Date: Fri, 21 Nov 1997 09:55:06 -0600
770Message-ID: <1234@local.machine.example>
771
772This is a message just to say hello.
773So, "Hello".`
774
Dusan Kasan45ca2642017-04-18 10:39:35 +0200775var rfc5322exampleA4 = `Received: from x.y.test
Dusan Kasanb49ceb62017-04-13 00:00:36 +0200776 by example.net
777 via TCP
778 with ESMTP
779 id ABC12345
780 for <mary@example.net>; 21 Nov 1997 10:05:43 -0600
781Received: from node.example by x.y.test; 21 Nov 1997 10:01:22 -0600
782From: John Doe <jdoe@node.example>
783To: Mary Smith <mary@example.net>
784Subject: Saying Hello
785Date: Fri, 21 Nov 1997 09:55:06 -0600
786Message-ID: <1234@local.node.example>
787
788This is a message just to say hello.
789So, "Hello".`
Dusan Kasan428369f2020-02-24 00:47:31 +0100790
791var imageContentExample = `From: John Doe <jdoe@machine.example>
792Sender: Michael Jones <mjones@machine.example>
793To: Mary Smith <mary@example.net>
794Subject: Saying Hello
795Date: Fri, 21 Nov 1997 09:55:06 -0600
796Message-ID: <1234@local.machine.example>
797Content-Type: image/jpeg;
798 x-unix-mode=0644;
799 name="image.gif"
800Content-Transfer-Encoding: base64
801
802R0lGODlhAQE7`