12	"github.com/mjl-/mox/dns"
 
13	"github.com/mjl-/mox/sasl"
 
14	"github.com/mjl-/mox/smtpclient"
 
18	// Submit a message to an SMTP server, with authentication. The SMTP server is
 
19	// responsible for getting the message delivered.
 
21	// Make TCP connection to submission server.
 
22	conn, err := net.Dial("tcp", "submit.example.org:465")
 
24		log.Fatalf("dial submission server: %v", err)
 
28	// Initialize the SMTP session, with a EHLO, STARTTLS and authentication.
 
29	// Verify the server TLS certificate with PKIX/WebPKI.
 
30	ctx := context.Background()
 
32	opts := smtpclient.Opts{
 
33		Auth: func(mechanisms []string, cs *tls.ConnectionState) (sasl.Client, error) {
 
34			// If the server is known to support a SCRAM PLUS variant, you should only use
 
35			// that, detecting and preventing authentication mechanism downgrade attacks
 
36			// through TLS channel binding.
 
38			password := "test1234"
 
40			// Prefer strongest authentication mechanism, allow up to older CRAM-MD5.
 
41			if cs != nil && slices.Contains(mechanisms, "SCRAM-SHA-256-PLUS") {
 
42				return sasl.NewClientSCRAMSHA256PLUS(username, password, *cs), nil
 
44			if slices.Contains(mechanisms, "SCRAM-SHA-256") {
 
45				return sasl.NewClientSCRAMSHA256(username, password, true), nil
 
47			if cs != nil && slices.Contains(mechanisms, "SCRAM-SHA-1-PLUS") {
 
48				return sasl.NewClientSCRAMSHA1PLUS(username, password, *cs), nil
 
50			if slices.Contains(mechanisms, "SCRAM-SHA-1") {
 
51				return sasl.NewClientSCRAMSHA1(username, password, true), nil
 
53			if slices.Contains(mechanisms, "CRAM-MD5") {
 
54				return sasl.NewClientCRAMMD5(username, password), nil
 
56			// No mutually supported mechanism found, connection will fail.
 
60	localname := dns.Domain{ASCII: "localhost"}
 
61	remotename := dns.Domain{ASCII: "submit.example.org"}
 
62	client, err := smtpclient.New(ctx, slog.Default(), conn, smtpclient.TLSImmediate, tlsVerifyPKIX, localname, remotename, opts)
 
64		log.Fatalf("initialize smtp to submission server: %v", err)
 
68	// Send the message to the server, which will add it to its queue.
 
69	req8bitmime := false // ASCII-only, so 8bitmime not required.
 
70	reqSMTPUTF8 := false // No UTF-8 headers, so smtputf8 not required.
 
71	requireTLS := false  // Not supported by most servers at the time of writing.
 
72	msg := "From: <mjl@example.org>\r\nTo: <other@example.org>\r\nSubject: hi\r\n\r\nnice to test you.\r\n"
 
73	err = client.Deliver(ctx, "mjl@example.org", "other@example.com", int64(len(msg)), strings.NewReader(msg), req8bitmime, reqSMTPUTF8, requireTLS)
 
75		log.Fatalf("submit message to smtp server: %v", err)
 
78	// Message has been submitted.