mox/quickstart_test.go
2023-06-22 21:27:52 +02:00

144 lines
4 KiB
Go

//go:build quickstart
// Run this using docker-compose.yml, see Makefile.
package main
import (
"crypto/tls"
"fmt"
"os"
"strings"
"testing"
"time"
"github.com/mjl-/mox/dns"
"github.com/mjl-/mox/imapclient"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/mox-"
"github.com/mjl-/mox/sasl"
"github.com/mjl-/mox/smtpclient"
)
var xlog = mlog.New("quickstart")
func tcheck(t *testing.T, err error, msg string) {
t.Helper()
if err != nil {
t.Fatalf("%s: %s", msg, err)
}
}
func TestDeliver(t *testing.T) {
mlog.Logfmt = true
hostname, err := os.Hostname()
tcheck(t, err, "hostname")
ourHostname, err := dns.ParseDomain(hostname)
tcheck(t, err, "parse hostname")
// Deliver submits a message over submissions, and checks with imap idle if the
// message is received by the destination mail server.
deliver := func(desthost, mailfrom, password, rcptto, imaphost, imapuser, imappassword string) {
t.Helper()
// Connect to IMAP, execute IDLE command, which will return on deliver message.
// TLS certificates work because the container has the CA certificates configured.
imapconn, err := tls.Dial("tcp", imaphost+":993", nil)
tcheck(t, err, "dial imap")
defer imapconn.Close()
imaperr := make(chan error, 1)
go func() {
go func() {
x := recover()
if x == nil {
return
}
imaperr <- x.(error)
}()
xcheck := func(err error, format string) {
if err != nil {
panic(fmt.Errorf("%s: %w", format, err))
}
}
imapc, err := imapclient.New(imapconn, false)
xcheck(err, "new imapclient")
_, _, err = imapc.Login(imapuser, imappassword)
xcheck(err, "imap login")
_, _, err = imapc.Select("Inbox")
xcheck(err, "imap select inbox")
err = imapc.Commandf("", "idle")
xcheck(err, "write imap idle command")
_, _, _, err = imapc.ReadContinuation()
xcheck(err, "read imap continuation")
done := make(chan error)
go func() {
defer func() {
x := recover()
if x != nil {
done <- fmt.Errorf("%v", x)
}
}()
untagged, err := imapc.ReadUntagged()
if err != nil {
done <- err
return
}
if _, ok := untagged.(imapclient.UntaggedExists); !ok {
done <- fmt.Errorf("expected imapclient.UntaggedExists, got %#v", untagged)
return
}
done <- nil
}()
period := 30 * time.Second
timer := time.NewTimer(period)
defer timer.Stop()
select {
case err = <-done:
case <-timer.C:
err = fmt.Errorf("nothing within %v", period)
}
xcheck(err, "waiting for imap untagged response to idle")
imaperr <- nil
}()
conn, err := tls.Dial("tcp", desthost+":465", nil)
tcheck(t, err, "dial submission")
defer conn.Close()
msg := fmt.Sprintf(`From: <%s>
To: <%s>
Subject: test message
This is the message.
`, mailfrom, rcptto)
msg = strings.ReplaceAll(msg, "\n", "\r\n")
auth := []sasl.Client{sasl.NewClientPlain(mailfrom, password)}
c, err := smtpclient.New(mox.Context, xlog, conn, smtpclient.TLSSkip, ourHostname, dns.Domain{ASCII: desthost}, auth)
tcheck(t, err, "smtp hello")
err = c.Deliver(mox.Context, mailfrom, rcptto, int64(len(msg)), strings.NewReader(msg), false, false)
tcheck(t, err, "deliver with smtp")
err = c.Close()
tcheck(t, err, "close smtpclient")
err = <-imaperr
tcheck(t, err, "imap idle")
}
xlog.Print("submitting email to moxacmepebble, waiting for imap notification at moxmail2, takes time because first-time sender")
t0 := time.Now()
deliver("moxacmepebble.mox1.example", "moxtest1@mox1.example", "accountpass1234", "moxtest2@mox2.example", "moxmail2.mox2.example", "moxtest2@mox2.example", "accountpass4321")
xlog.Print("success", mlog.Field("duration", time.Since(t0)))
xlog.Print("submitting email to moxmail2, waiting for imap notification at moxacmepebble, takes time because first-time sender")
t0 = time.Now()
deliver("moxmail2.mox2.example", "moxtest2@mox2.example", "accountpass4321", "moxtest1@mox1.example", "moxacmepebble.mox1.example", "moxtest1@mox1.example", "accountpass1234")
xlog.Print("success", mlog.Field("duration", time.Since(t0)))
}