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 msg = strings.ReplaceAll(`From: <private@mox.example>
44To: <private@mox.example>
50 ts.run(func(err error, client *smtpclient.Client) {
52 mailFrom := "mjl@mox.example"
53 rcptTo := "private@mox.example"
55 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
57 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
61// Non-member cannot submit as alias that allows it for members.
62func TestAliasSubmitMsgFromDenied(t *testing.T) {
63 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), dns.MockResolver{})
66 // Trying to open account by alias should result in proper error.
67 _, _, err := store.OpenEmail(pkglog, "public@mox.example")
68 if err == nil || !errors.Is(err, store.ErrUnknownCredentials) {
69 t.Fatalf("opening alias, got err %v, expected store.ErrUnknownCredentials", err)
72 acc, err := store.OpenAccount(pkglog, "☺")
73 tcheck(t, err, "open account")
74 err = acc.SetPassword(pkglog, password0)
75 tcheck(t, err, "set password")
77 tcheck(t, err, "close account")
81 ts.user = "☺@mox.example"
84 var msg = strings.ReplaceAll(`From: <public@mox.example>
85To: <public@mox.example>
91 ts.run(func(err error, client *smtpclient.Client) {
93 mailFrom := "☺@mox.example"
94 rcptTo := "public@mox.example"
96 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
98 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7DeliveryUnauth1})
102// Non-member can deliver to public list, not to private list.
103func TestAliasDeliverNonMember(t *testing.T) {
104 resolver := dns.MockResolver{
105 A: map[string][]string{
106 "example.org.": {"127.0.0.10"}, // For mx check.
108 PTR: map[string][]string{
109 "127.0.0.10": {"example.org."}, // To get passed junk filter.
112 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
115 var msg = strings.ReplaceAll(`From: <other@example.org>
116To: <private@mox.example>
121 ts.run(func(err error, client *smtpclient.Client) {
123 mailFrom := "other@example.org"
124 rcptTo := "private@mox.example"
126 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
128 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
131 msg = strings.ReplaceAll(`From: <private@mox.example>
132To: <private@mox.example>
137 ts.run(func(err error, client *smtpclient.Client) {
139 mailFrom := "private@example.org"
140 rcptTo := "private@mox.example"
142 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
144 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
147 msg = strings.ReplaceAll(`From: <other@example.org>
148To: <public@mox.example>
154 ts.run(func(err error, client *smtpclient.Client) {
156 mailFrom := "other@example.org"
157 rcptTo := "public@mox.example"
159 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
163 ts.checkCount("Inbox", 2) // Receiving for both mjl@ and móx@.
167// Member can deliver to private list, but still not with alias address as message
168// from. Message with alias from address as message from is allowed.
169func TestAliasDeliverMember(t *testing.T) {
170 resolver := dns.MockResolver{
171 A: map[string][]string{
172 "mox.example.": {"127.0.0.10"}, // For mx check.
174 PTR: map[string][]string{
175 "127.0.0.10": {"mox.example."}, // To get passed junk filter.
177 TXT: map[string][]string{
178 "mox.example.": {"v=spf1 ip4:127.0.0.10 -all"}, // To allow multiple recipients in transaction.
181 ts := newTestServer(t, filepath.FromSlash("../testdata/smtp/mox.conf"), resolver)
184 var msg = strings.ReplaceAll(`From: <mjl@mox.example>
185To: <private@mox.example>
190 ts.run(func(err error, client *smtpclient.Client) {
192 mailFrom := "mjl@mox.example"
193 rcptTo := []string{"private@mox.example", "móx@mox.example"}
195 _, err = client.DeliverMultiple(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), true, true, false)
196 // assuming there wasn't a per-recipient error
200 ts.checkCount("Inbox", 0) // Not receiving for mjl@ due to msgfrom, and not móx@ due to rcpt to.
203 ts.run(func(err error, client *smtpclient.Client) {
205 mailFrom := "mjl@mox.example"
206 rcptTo := "private@mox.example"
208 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
212 ts.checkCount("Inbox", 1) // Only receiving for móx@mox.example, not mjl@.
215 msg = strings.ReplaceAll(`From: <private@mox.example>
216To: <private@mox.example>
222 ts.run(func(err error, client *smtpclient.Client) {
224 mailFrom := "other@mox.example"
225 rcptTo := "private@mox.example"
227 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
229 ts.smtpErr(err, &smtpclient.Error{Permanent: true, Code: smtp.C550MailboxUnavail, Secode: smtp.SePol7ExpnProhibited2})
232 msg = strings.ReplaceAll(`From: <public@mox.example>
233To: <public@mox.example>
239 ts.run(func(err error, client *smtpclient.Client) {
241 mailFrom := "mjl@mox.example"
242 rcptTo := "public@mox.example"
244 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(err error, client *smtpclient.Client) {
274 mailFrom := "mjl@mox.example"
275 rcptTo := "private@mox.example"
277 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
281 ts.checkCount("Inbox", 1) // Only receiving for móx@mox.example, not mjl@.
284 // Mark message as junk.
285 q := bstore.QueryDB[store.Message](ctxbg, ts.acc.DB)
286 n, err := q.UpdateFields(map[string]any{"Junk": true})
287 tcheck(t, err, "mark as junk")
290 ts.run(func(err error, client *smtpclient.Client) {
292 mailFrom := "mjl@mox.example"
293 rcptTo := "private@mox.example"
295 err = client.Deliver(ctxbg, mailFrom, rcptTo, int64(len(msg)), strings.NewReader(msg), false, false, false)
297 ts.smtpErr(err, &smtpclient.Error{Code: smtp.C451LocalErr, Secode: smtp.SeSys3Other0})