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(client *smtpclient.Client) {
34 mailFrom := "mjl@mox.example"
35 rcptTo := "public@mox.example"
36 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
40 ts.run(func(client *smtpclient.Client) {
41 mailFrom := "public@mox.example" // List address as smtp mail from.
42 rcptTo := "public@mox.example"
43 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
47 msg = strings.ReplaceAll(`From: <private@mox.example>
48To: <private@mox.example>
54 ts.run(func(client *smtpclient.Client) {
55 mailFrom := "mjl@mox.example"
56 rcptTo := "private@mox.example"
57 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
58 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
61 ts.run(func(client *smtpclient.Client) {
62 mailFrom := "private@mox.example" // List address as smtp mail from.
63 rcptTo := "private@mox.example"
64 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
65 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
69// Non-member cannot submit as alias that allows it for members.
70func TestAliasSubmitMsgFromDenied(t *testing.T) {
71 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), dns.MockResolver{})
74 // Trying to open account by alias should result in proper error.
75 _, _, _, err := store.OpenEmail(pkglog, "public@mox.example", false)
76 if err == nil || !errors.Is(err, store.ErrUnknownCredentials) {
77 t.Fatalf("opening alias, got err %v, expected store.ErrUnknownCredentials", err)
80 acc, err := store.OpenAccount(pkglog, "☺", false)
81 tcheck(t, err, "open account")
82 err = acc.SetPassword(pkglog, password0)
83 tcheck(t, err, "set password")
85 tcheck(t, err, "close account")
89 ts.user = "☺@mox.example"
92 var msg = strings.ReplaceAll(`From: <public@mox.example>
93To: <public@mox.example>
99 ts.run(func(client *smtpclient.Client) {
100 mailFrom := "☺@mox.example"
101 rcptTo := "public@mox.example"
102 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
103 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
106 ts.run(func(client *smtpclient.Client) {
107 mailFrom := "public@mox.example" // List address as message from.
108 rcptTo := "public@mox.example"
109 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
110 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
114// Non-member can deliver to public list, not to private list.
115func TestAliasDeliverNonMember(t *testing.T) {
116 resolver := dns.MockResolver{
117 A: map[string][]string{
118 "example.org.": {"127.0.0.10"}, // For mx check.
120 PTR: map[string][]string{
121 "127.0.0.10": {"example.org."}, // To get passed junk filter.
124 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
127 var msg = strings.ReplaceAll(`From: <other@example.org>
128To: <private@mox.example>
133 ts.run(func(client *smtpclient.Client) {
134 mailFrom := "other@example.org"
135 rcptTo := "private@mox.example"
136 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
137 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
140 msg = strings.ReplaceAll(`From: <private@mox.example>
141To: <private@mox.example>
146 ts.run(func(client *smtpclient.Client) {
147 mailFrom := "private@example.org"
148 rcptTo := "private@mox.example"
149 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
150 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
153 msg = strings.ReplaceAll(`From: <other@example.org>
154To: <public@mox.example>
160 ts.run(func(client *smtpclient.Client) {
161 mailFrom := "other@example.org"
162 rcptTo := "public@mox.example"
163 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
166 ts.checkCount("Inbox", 2) // Receiving for both mjl@ and móx@.
169 ts.run(func(client *smtpclient.Client) {
170 mailFrom := "public@example.org" // List address as message from.
171 rcptTo := "public@mox.example"
172 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
175 ts.checkCount("Inbox", 4) // Receiving for both mjl@ and móx@.
179// Member can deliver to private list, but still not with alias address as message
180// from. Message with alias from address as message from is allowed.
181func TestAliasDeliverMember(t *testing.T) {
182 resolver := dns.MockResolver{
183 A: map[string][]string{
184 "mox.example.": {"127.0.0.10"}, // For mx check.
186 PTR: map[string][]string{
187 "127.0.0.10": {"mox.example."}, // To get passed junk filter.
189 TXT: map[string][]string{
190 "mox.example.": {"v=spf1 ip4:127.0.0.10 -all"}, // To allow multiple recipients in transaction.
193 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
196 var msg = strings.ReplaceAll(`From: <mjl@mox.example>
197To: <private@mox.example>
202 ts.run(func(client *smtpclient.Client) {
203 mailFrom := "mjl@mox.example"
204 rcptTo := []string{"private@mox.example", "móx@mox.example"}
205 _, err := client.DeliverMultiple(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
206 // assuming there wasn't a per-recipient error
209 ts.checkCount("Inbox", 1) // Receiving once. For explicit móx@ recipient, not for mjl@ due to msgfrom, and another again for móx@ due to rcpt to.
212 ts.run(func(client *smtpclient.Client) {
213 mailFrom := "mjl@mox.example"
214 rcptTo := "private@mox.example"
215 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
218 ts.checkCount("Inbox", 2) // Only receiving 1 new message compared to previous, for móx@mox.example, not mjl@.
221 msg = strings.ReplaceAll(`From: <private@mox.example>
222To: <private@mox.example>
228 ts.run(func(client *smtpclient.Client) {
229 mailFrom := "other@mox.example"
230 rcptTo := "private@mox.example"
231 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
232 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
235 msg = strings.ReplaceAll(`From: <public@mox.example>
236To: <public@mox.example>
242 ts.run(func(client *smtpclient.Client) {
243 mailFrom := "mjl@mox.example"
244 rcptTo := "public@mox.example"
245 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
250// Message is rejected if no member accepts it.
251func TestAliasDeliverReject(t *testing.T) {
252 resolver := dns.MockResolver{
253 A: map[string][]string{
254 "mox.example.": {"127.0.0.10"}, // For mx check.
256 PTR: map[string][]string{
257 "127.0.0.10": {"mox.example."}, // To get passed junk filter.
259 TXT: map[string][]string{
260 "mox.example.": {"v=spf1 ip4:127.0.0.10 -all"}, // To allow multiple recipients in transaction.
263 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
266 var msg = strings.ReplaceAll(`From: <mjl@mox.example>
267To: <private@mox.example>
272 ts.run(func(client *smtpclient.Client) {
273 mailFrom := "mjl@mox.example"
274 rcptTo := "private@mox.example"
275 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
278 ts.checkCount("Inbox", 1) // Only receiving for móx@mox.example, not mjl@.
281 // Mark message as junk.
282 q := bstore.QueryDB[store.Message](ctxbg, ts.acc.DB)
283 n, err := q.UpdateFields(map[string]any{"Junk": true})
284 tcheck(t, err, "mark as junk")
287 ts.run(func(client *smtpclient.Client) {
288 mailFrom := "mjl@mox.example"
289 rcptTo := "private@mox.example"
290 err := client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
291 ts.smtpErr(err, &smtpclient.Error{Code: smtp.C451LocalErr, Secode: smtp.SeSys3Other0})