9 "github.com/mjl-/bstore"
11 "github.com/mjl-/mox/dns"
12 "github.com/mjl-/mox/smtp"
13 "github.com/mjl-/mox/smtpclient"
14 "github.com/mjl-/mox/store"
17// Check user can submit message with message From address they are member of.
18func TestAliasSubmitMsgFrom(t *testing.T) {
19 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), dns.MockResolver{})
23 ts.user = "mjl@mox.example"
26 var msg = strings.ReplaceAll(`From: <public@mox.example>
27To: <public@mox.example>
33 ts.run(func(err error, client *smtpclient.Client) {
35 mailFrom := "mjl@mox.example"
36 rcptTo := "public@mox.example"
38 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
43 ts.run(func(err error, client *smtpclient.Client) {
45 mailFrom := "public@mox.example" // List address as smtp mail from.
46 rcptTo := "public@mox.example"
48 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
53 msg = strings.ReplaceAll(`From: <private@mox.example>
54To: <private@mox.example>
60 ts.run(func(err error, client *smtpclient.Client) {
62 mailFrom := "mjl@mox.example"
63 rcptTo := "private@mox.example"
65 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
67 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
70 ts.run(func(err error, client *smtpclient.Client) {
72 mailFrom := "private@mox.example" // List address as smtp mail from.
73 rcptTo := "private@mox.example"
75 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
77 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
81// Non-member cannot submit as alias that allows it for members.
82func TestAliasSubmitMsgFromDenied(t *testing.T) {
83 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), dns.MockResolver{})
86 // Trying to open account by alias should result in proper error.
87 _, _, err := store.OpenEmail(pkglog, "public@mox.example")
88 if err == nil || !errors.Is(err, store.ErrUnknownCredentials) {
89 t.Fatalf("opening alias, got err %v, expected store.ErrUnknownCredentials", err)
92 acc, err := store.OpenAccount(pkglog, "☺")
93 tcheck(t, err, "open account")
94 err = acc.SetPassword(pkglog, password0)
95 tcheck(t, err, "set password")
97 tcheck(t, err, "close account")
101 ts.user = "☺@mox.example"
104 var msg = strings.ReplaceAll(`From: <public@mox.example>
105To: <public@mox.example>
111 ts.run(func(err error, client *smtpclient.Client) {
113 mailFrom := "☺@mox.example"
114 rcptTo := "public@mox.example"
116 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
118 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
121 ts.run(func(err error, client *smtpclient.Client) {
123 mailFrom := "public@mox.example" // List address as message from.
124 rcptTo := "public@mox.example"
126 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
128 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
132// Non-member can deliver to public list, not to private list.
133func TestAliasDeliverNonMember(t *testing.T) {
134 resolver := dns.MockResolver{
135 A: map[string][]string{
136 "example.org.": {"127.0.0.10"}, // For mx check.
138 PTR: map[string][]string{
139 "127.0.0.10": {"example.org."}, // To get passed junk filter.
142 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
145 var msg = strings.ReplaceAll(`From: <other@example.org>
146To: <private@mox.example>
151 ts.run(func(err error, client *smtpclient.Client) {
153 mailFrom := "other@example.org"
154 rcptTo := "private@mox.example"
156 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
158 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
161 msg = strings.ReplaceAll(`From: <private@mox.example>
162To: <private@mox.example>
167 ts.run(func(err error, client *smtpclient.Client) {
169 mailFrom := "private@example.org"
170 rcptTo := "private@mox.example"
172 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
174 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
177 msg = strings.ReplaceAll(`From: <other@example.org>
178To: <public@mox.example>
184 ts.run(func(err error, client *smtpclient.Client) {
186 mailFrom := "other@example.org"
187 rcptTo := "public@mox.example"
189 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
193 ts.checkCount("Inbox", 2) // Receiving for both mjl@ and móx@.
196 ts.run(func(err error, client *smtpclient.Client) {
198 mailFrom := "public@example.org" // List address as message from.
199 rcptTo := "public@mox.example"
201 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
205 ts.checkCount("Inbox", 4) // Receiving for both mjl@ and móx@.
209// Member can deliver to private list, but still not with alias address as message
210// from. Message with alias from address as message from is allowed.
211func TestAliasDeliverMember(t *testing.T) {
212 resolver := dns.MockResolver{
213 A: map[string][]string{
214 "mox.example.": {"127.0.0.10"}, // For mx check.
216 PTR: map[string][]string{
217 "127.0.0.10": {"mox.example."}, // To get passed junk filter.
219 TXT: map[string][]string{
220 "mox.example.": {"v=spf1 ip4:127.0.0.10 -all"}, // To allow multiple recipients in transaction.
223 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
226 var msg = strings.ReplaceAll(`From: <mjl@mox.example>
227To: <private@mox.example>
232 ts.run(func(err error, client *smtpclient.Client) {
234 mailFrom := "mjl@mox.example"
235 rcptTo := []string{"private@mox.example", "móx@mox.example"}
237 _, err = client.DeliverMultiple(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
238 // assuming there wasn't a per-recipient error
242 ts.checkCount("Inbox", 0) // Not receiving for mjl@ due to msgfrom, and not móx@ due to rcpt to.
245 ts.run(func(err error, client *smtpclient.Client) {
247 mailFrom := "mjl@mox.example"
248 rcptTo := "private@mox.example"
250 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
254 ts.checkCount("Inbox", 1) // Only receiving for móx@mox.example, not mjl@.
257 msg = strings.ReplaceAll(`From: <private@mox.example>
258To: <private@mox.example>
264 ts.run(func(err error, client *smtpclient.Client) {
266 mailFrom := "other@mox.example"
267 rcptTo := "private@mox.example"
269 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
271 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
274 msg = strings.ReplaceAll(`From: <public@mox.example>
275To: <public@mox.example>
281 ts.run(func(err error, client *smtpclient.Client) {
283 mailFrom := "mjl@mox.example"
284 rcptTo := "public@mox.example"
286 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
292// Message is rejected if no member accepts it.
293func TestAliasDeliverReject(t *testing.T) {
294 resolver := dns.MockResolver{
295 A: map[string][]string{
296 "mox.example.": {"127.0.0.10"}, // For mx check.
298 PTR: map[string][]string{
299 "127.0.0.10": {"mox.example."}, // To get passed junk filter.
301 TXT: map[string][]string{
302 "mox.example.": {"v=spf1 ip4:127.0.0.10 -all"}, // To allow multiple recipients in transaction.
305 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
308 var msg = strings.ReplaceAll(`From: <mjl@mox.example>
309To: <private@mox.example>
314 ts.run(func(err error, client *smtpclient.Client) {
316 mailFrom := "mjl@mox.example"
317 rcptTo := "private@mox.example"
319 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
323 ts.checkCount("Inbox", 1) // Only receiving for móx@mox.example, not mjl@.
326 // Mark message as junk.
327 q := bstore.QueryDB[store.Message](ctxbg, ts.acc.DB)
328 n, err := q.UpdateFields(map[string]any{"Junk": true})
329 tcheck(t, err, "mark as junk")
332 ts.run(func(err error, client *smtpclient.Client) {
334 mailFrom := "mjl@mox.example"
335 rcptTo := "private@mox.example"
337 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
339 ts.smtpErr(err, &smtpclient.Error{Code: smtp.C451LocalErr, Secode: smtp.SeSys3Other0})