-
Notifications
You must be signed in to change notification settings - Fork 5
/
header_test.go
236 lines (199 loc) · 7.14 KB
/
header_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package mail_test
import (
"fmt"
"os"
"testing"
"time"
"io/ioutil"
"github.com/paulrosania/go-mail"
)
func loadFixture(t *testing.T, name string) *mail.Message {
filename := fmt.Sprintf("fixtures/%s.eml", name)
f, err := os.Open(filename)
if err != nil {
t.Fatal(err)
}
body, err := ioutil.ReadAll(f)
if err != nil {
t.Fatal(err)
}
msg, err := mail.ReadMessage(string(body))
if err != nil {
t.Fatal(err)
}
if msg == nil {
t.Fatalf("**VERY BAD** ReadMessage returned nil with no error")
}
return msg
}
func testStringEquals(t *testing.T, field, actual, expected string) {
if actual != expected {
t.Errorf("incorrect %s:\nexpected %q,\n got %q", field, expected, actual)
}
}
func testIntegerEquals(t *testing.T, field string, actual, expected int) {
if actual != expected {
t.Errorf("incorrect %s:\nexpected %d,\n got %d", field, expected, actual)
}
}
// Error(args ...interface{})
// Errorf(format string, args ...interface{})
// Fail()
// FailNow()
// Failed() bool
// Fatal(args ...interface{})
// Fatalf(format string, args ...interface{})
// Log(args ...interface{})
// Logf(format string, args ...interface{})
// Skip(args ...interface{})
// SkipNow()
// Skipf(format string, args ...interface{})
// Skipped() bool
func TestContentType(t *testing.T) {
msg := loadFixture(t, "basic")
if msg.Header == nil {
t.Fatal("missing Header struct")
}
ct := msg.Header.ContentType()
if ct == nil {
t.Error("missing Content-Type")
} else if ct.Type != "text" || ct.Subtype != "html" {
t.Errorf("incorrect Content-Type: expected text/html, got %s/%s", ct.Type, ct.Subtype)
}
}
func TestAddressFields(t *testing.T) {
msg := loadFixture(t, "basic")
if msg.Header == nil {
t.Fatal("missing Header struct")
}
from := msg.Header.Addresses("From")
if len(from) != 5 {
t.Errorf("incorrect number of From addresses: expected 5, got %d", len(from))
} else {
testStringEquals(t, "From address", from[0].String(), "[email protected]")
testStringEquals(t, "From address", from[1].String(), "Full From <[email protected]>")
testStringEquals(t, "From address", from[2].String(), "[email protected]")
testStringEquals(t, "From address", from[3].String(), "[email protected]")
testStringEquals(t, "From address", from[4].String(), "[email protected]")
}
to := msg.Header.Addresses("To")
if len(to) != 1 {
t.Errorf("incorrect number of To addresses: expected 1, got %d", len(to))
} else {
testStringEquals(t, "To address", to[0].String(), "[email protected]")
}
// Test requests for missing address headers
cc := msg.Header.Addresses("Cc")
if len(cc) != 0 {
t.Errorf("incorrect number of Cc addresses: expected 0, got %d", len(cc))
}
}
func TestCFWS(t *testing.T) {
msg := loadFixture(t, "cfws")
if msg.Header == nil {
t.Fatal("missing Header struct")
}
from := msg.Header.Addresses("From")
if len(from) != 1 {
t.Errorf("incorrect number of From addresses: expected 1, got %d", len(from))
} else if from[0].String() != "Pete <[email protected]>" {
t.Errorf("incorrect From address: expected \"Pete <[email protected]>\", got %s", from[0].String())
}
to := msg.Header.Addresses("To")
if len(to) != 3 {
t.Errorf("incorrect number of To addresses: expected 3, got %d", len(to))
} else {
testStringEquals(t, "To address", to[0].String(), "Chris Jones <[email protected]>")
testStringEquals(t, "To address", to[1].String(), "[email protected]")
testStringEquals(t, "To address", to[2].String(), "John <[email protected]>")
}
cc := msg.Header.Addresses("Cc")
if len(cc) != 0 {
t.Errorf("incorrect number of Cc addresses: expected 0, got %d", len(cc))
}
date := msg.Header.Date()
if date == nil {
t.Errorf("missing or invalid date field in header")
} else {
testStringEquals(t, "Date", date.Format(time.RFC822), "13 Feb 69 23:32 -0330")
}
messageID := msg.Header.MessageID()
testStringEquals(t, "Message-ID", messageID, "<[email protected]>")
}
// Relevant RFC: https://tools.ietf.org/html/rfc2047
func TestEncodedWords(t *testing.T) {
msg := loadFixture(t, "encoded-words")
if msg.Header == nil {
t.Fatal("missing Header struct")
}
subject := msg.Header.Subject()
if subject != "Testing encoded words! ☺" {
t.Errorf("incorrect Subject: expected \"Testing encoded words! ☺\", got %s", subject)
}
from := msg.Header.Addresses("From")
if len(from) != 1 {
t.Errorf("incorrect number of From addresses: expected 1, got %d", len(from))
} else if from[0].String() != "invalid quotes <[email protected]>" {
t.Errorf("incorrect From address: expected \"invalid quotes <[email protected]>\", got %s", from[0].String())
}
// Test for non-standard "Q"-encoding: the Reply-To header in this fixture
// contains a '.' in a Q-encoded word within a phrase.
//
// From RFC 2047:
//
// An 'encoded-word' may appear in a message header or body part header
// according to the following rules:
//
// [...]
//
// (3) As a replacement for a 'word' entity within a 'phrase', for example,
// one that precedes an address in a From, To, or Cc header. The ABNF
// definition for 'phrase' from RFC 822 thus becomes:
//
// phrase = 1*( encoded-word / word )
//
// In this case the set of characters that may be used in a "Q"-encoded
// 'encoded-word' is restricted to: <upper and lower case ASCII
// letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
// (underscore, ASCII 95.)>. An 'encoded-word' that appears within a
// 'phrase' MUST be separated from any adjacent 'word', 'text' or
// 'special' by 'linear-white-space'.
//
// Note: go-mail outputs a quoted name, since dots in phrases are obsolete.
// (See RFC 5322 Section 4.1)
replyTo := msg.Header.Addresses("Reply-To")
if len(replyTo) != 1 {
t.Errorf("incorrect number of Reply-To addresses: expected 1, got %d", len(replyTo))
} else if replyTo[0].String() != `"contains an in.valid dot" <[email protected]>` {
t.Errorf("incorrect Reply-To address: expected \"\"contains an in.valid dot\" <[email protected]>\", got %s", replyTo[0].String())
}
// Test valid "Q"-encoding
to := msg.Header.Addresses("To")
if len(to) != 2 {
t.Errorf("incorrect number of To addresses: expected 2, got %d", len(to))
} else {
if to[0].String() != "valid <[email protected]>" {
t.Errorf("incorrect To address: expected \"valid <[email protected]>\", got %s", to[0].String())
}
if to[1].String() != "mixed example <[email protected]>" {
t.Errorf("incorrect To address: expected \"mixed example <[email protected]>\", got %s", to[1].String())
}
}
}
func TestMessageID(t *testing.T) {
msg := loadFixture(t, "message-id")
if msg.Header == nil {
t.Fatal("missing Header struct")
}
msgid := msg.Header.MessageID()
if msgid != "<valid@message-id>" {
t.Errorf("incorrect Message-ID: expected <valid@message-id>, got %s", msgid)
}
parts := msg.Parts
if len(parts) != 2 {
t.Errorf("incorrect number of message parts: expected 2, got %d", len(parts))
t.FailNow()
}
testStringEquals(t, "Part 1 Content-ID", parts[0].Header.Get("Content-ID"), "<invalid-id-with-no-brackets>")
testStringEquals(t, "Part 2 Content-ID", parts[1].Header.Get("Content-ID"), "<valid-id@example>")
}