package smtpserver import ( "net/smtp" "strings" "testing" "mailgoserver/internal/db" "mailgoserver/internal/mailstore" ) // newTestBackendWithMailbox extends newTestBackend with a live Mailstore and one // mailbox, inbox@example.com, on the same verified example.com domain used by the // rest of this package's tests. func newTestBackendWithMailbox(t *testing.T) (*Backend, int64) { t.Helper() backend := newTestBackend(t) store := mailstore.New(backend.DB, mailstore.GenerateDEK(), t.TempDir()) backend.Mailstore = store // Spam/SPF/DNSBL checks make live DNS calls (see internal/mailstore) — deliberately // so in production, but that makes their exact score environment-dependent (e.g. a // resolver that hijacks NXDOMAIN, or a real SPF record on the test domain). These // tests exercise local-delivery wiring, not spam-scoring accuracy (see // internal/mailstore's own tests for that), so disable rejection entirely here. backend.Cfg.Section("Mailstore").Key("spam_reject_score").SetValue("1000000") dek := mailstore.GenerateDEK() wrapped, nonce, err := store.WrapDEK(dek) if err != nil { t.Fatal(err) } hash, err := db.HashPassword("portal-password-unused") if err != nil { t.Fatal(err) } mailboxID, err := backend.DB.CreateMailbox("inbox@example.com", hash, 1, 5*1024*1024*1024, wrapped, nonce) if err != nil { t.Fatal(err) } return backend, mailboxID } func TestLocalDeliveryToKnownMailbox(t *testing.T) { backend, mailboxID := newTestBackendWithMailbox(t) addr := startTestServer(t, backend) c, err := smtp.Dial(addr) if err != nil { t.Fatal(err) } defer c.Close() if err := c.Auth(smtp.PlainAuth("", "test@example.com", "testpass123", "127.0.0.1")); err != nil { t.Fatalf("auth: %v", err) } if err := c.Mail("test@example.com"); err != nil { t.Fatalf("MAIL FROM: %v", err) } if err := c.Rcpt("inbox@example.com"); err != nil { t.Fatalf("expected RCPT to a real local mailbox to succeed, got: %v", err) } w, err := c.Data() if err != nil { t.Fatal(err) } if _, err := w.Write([]byte("Subject: hello\r\n\r\nhi there")); err != nil { t.Fatal(err) } if err := w.Close(); err != nil { t.Fatalf("expected DATA to succeed for local delivery, got: %v", err) } mbox, err := backend.DB.GetMailboxByID(mailboxID) if err != nil { t.Fatal(err) } if mbox.UsedBytes == 0 { t.Fatal("expected mailbox used_bytes to increase after local delivery") } } func TestLocalDeliveryUnknownMailboxRejected(t *testing.T) { backend, _ := newTestBackendWithMailbox(t) addr := startTestServer(t, backend) c, err := smtp.Dial(addr) if err != nil { t.Fatal(err) } defer c.Close() if err := c.Auth(smtp.PlainAuth("", "test@example.com", "testpass123", "127.0.0.1")); err != nil { t.Fatalf("auth: %v", err) } if err := c.Mail("test@example.com"); err != nil { t.Fatalf("MAIL FROM: %v", err) } err = c.Rcpt("nobody@example.com") if err == nil { t.Fatal("expected RCPT to an unknown address on a locally-configured domain to be rejected") } if !strings.Contains(err.Error(), "550") { t.Fatalf("expected 550 response, got: %v", err) } } func TestExternalSenderCanOnlyDeliverLocally(t *testing.T) { backend, _ := newTestBackendWithMailbox(t) addr := startTestServer(t, backend) c, err := smtp.Dial(addr) if err != nil { t.Fatal(err) } defer c.Close() // No AUTH, no whitelist match: MAIL FROM an entirely unconfigured external // domain must be provisionally accepted (Mailstore is enabled) ... if err := c.Mail("someone@external.example"); err != nil { t.Fatalf("expected MAIL FROM from an external domain to be provisionally accepted, got: %v", err) } // ... but RCPT to an external address must still be denied (not an open relay). err = c.Rcpt("other@somewhere-else.example") if err == nil { t.Fatal("expected RCPT to an external address to be denied for an unauthorized sender") } if !strings.Contains(err.Error(), "550") { t.Fatalf("expected 550 response, got: %v", err) } // RCPT to our local mailbox must still succeed for the same provisionally // accepted sender — this is the whole point of accepting it. if err := c.Rcpt("inbox@example.com"); err != nil { t.Fatalf("expected RCPT to a local mailbox to succeed for an external sender, got: %v", err) } } func TestAuthorizedSenderStillRelaysExternallyWithMailstoreEnabled(t *testing.T) { backend, _ := newTestBackendWithMailbox(t) addr := startTestServer(t, backend) c, err := smtp.Dial(addr) if err != nil { t.Fatal(err) } defer c.Close() if err := c.Auth(smtp.PlainAuth("", "test@example.com", "testpass123", "127.0.0.1")); err != nil { t.Fatalf("auth: %v", err) } if err := c.Mail("test@example.com"); err != nil { t.Fatalf("MAIL FROM: %v", err) } if err := c.Rcpt("someone@elsewhere.example"); err != nil { t.Fatalf("expected an authorized sender's relay RCPT to still be accepted with Mailstore enabled, got: %v", err) } }