### Create SMTP Server Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Initializes and starts a new SMTP server instance. ```go s := smtp.NewServer(backend) s.Addr = "localhost:1025" s.ListenAndServe() ``` -------------------------------- ### Start the SMTP server with TLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Configure and start a secure SMTP server. Ensure TLSConfig is populated before calling this method. ```go cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem") if err != nil { log.Fatal(err) } tlsConfig := &tls.Config{ Certificates: []tls.Certificate{cert}, } server := smtp.NewServer(backend) server.TLSConfig = tlsConfig server.Addr = "localhost:465" server.Domain = "localhost" if err := server.ListenAndServeTLS(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Implement Backend and Session Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Example implementation of a custom Backend and Session struct. ```go type MyBackend struct{} func (b *MyBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { return &MySession{}, nil } type MySession struct{} func (s *MySession) Reset() {} func (s *MySession) Logout() error { return nil } func (s *MySession) Mail(from string, opts *smtp.MailOptions) error { return nil } func (s *MySession) Rcpt(to string, opts *smtp.RcptOptions) error { return nil } func (s *MySession) Data(r io.Reader) error { return nil } ``` -------------------------------- ### Start the SMTP server with ListenAndServe Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Begin listening for incoming connections on the configured address. ```go server := smtp.NewServer(backend) server.Addr = "localhost:1025" server.Domain = "localhost" server.MaxMessageBytes = 1024 * 1024 log.Println("Starting SMTP server on", server.Addr) if err := server.ListenAndServe(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Use BackendFunc Adapter Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Example of using a function instead of a struct to implement the Backend interface. ```go // Using BackendFunc to avoid creating a struct backend := smtp.BackendFunc(func(c *smtp.Conn) (smtp.Session, error) { return &MySession{}, nil }) server := smtp.NewServer(backend) ``` -------------------------------- ### Handle 502 Command Not Implemented Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of checking for extension support before executing a command. ```go client, _ := smtp.Dial("mail.example.com:25") // Server doesn't advertise STARTTLS _, ok := client.Extension("STARTTLS") if !ok { err := client.startTLS(nil) // Returns: "smtp: server doesn't support STARTTLS" } ``` -------------------------------- ### ListenAndServe() error Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Starts the SMTP server by listening on the configured network address. ```APIDOC ## ListenAndServe() error ### Description Listens on the network address s.Addr and then calls Serve to handle requests on incoming connections. If s.Addr is blank and LMTP is disabled, ":smtp" (port 25) is used as the default address. ### Returns - **error** - Error from listening or serving ``` -------------------------------- ### Run an authenticated submission server Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/package-overview.md Starts an SMTP submission server on port 587 with TLS enabled. ```go s := smtp.NewServer(&SubmissionBackend{}) s.Addr = "localhost:587" s.TLSConfig = tlsConfig s.ListenAndServe() ``` -------------------------------- ### Configure Server Logger Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Example of assigning a standard library logger to the server's ErrorLog field. ```go import "log" server := smtp.NewServer(backend) server.ErrorLog = log.New(os.Stderr, "smtp: ", log.LstdFlags) ``` -------------------------------- ### Handle 220 Service Ready response Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of establishing a connection and receiving the initial server greeting. ```go client, err := smtp.Dial("mail.example.com:25") // 220 mail.example.com ESMTP ready ``` -------------------------------- ### Session Implementation Using Conn Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/conn.md Example of implementing a session that utilizes the Conn object for connection information and authorization checks. ```go type MySession struct { conn *smtp.Conn from string rcpts []string } func (b *MyBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { // Access connection information during session creation hostname := c.Hostname() tlsState, hasTLS := c.TLSConnectionState() log.Printf("New session from %s (TLS: %v)", hostname, hasTLS) return &MySession{ conn: c, }, nil } func (s *MySession) Mail(from string, opts *smtp.MailOptions) error { // Use connection for authorization checks if opts != nil && opts.RequireTLS { _, hasTLS := s.conn.TLSConnectionState() if !hasTLS { return errors.New("TLS required") } } s.from = from return nil } func (s *MySession) Rcpt(to string, opts *smtp.RcptOptions) error { s.rcpts = append(s.rcpts, to) return nil } func (s *MySession) Data(r io.Reader) error { // Process message _, _ = io.ReadAll(r) return nil } func (s *MySession) Reset() { s.from = "" s.rcpts = nil } func (s *MySession) Logout() error { return nil } ``` -------------------------------- ### ListenAndServeTLS() error Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Starts the SMTP server using TLS on the configured network address. ```APIDOC ## ListenAndServeTLS() error ### Description Listens on the TCP network address s.Addr using TLS and then calls Serve to handle requests on incoming TLS connections. s.TLSConfig must be set before calling this method. If s.Addr is blank and LMTP is disabled, ":smtps" (port 465) is used as the default address. ### Returns - **error** - Error from listening or serving ``` -------------------------------- ### Handle 504 Command Parameter Not Implemented Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of a client attempting to use SMTPUTF8 on a server that does not support it. ```go client, _ := smtp.DialStartTLS("mail.example.com:587", nil) client.Mail("sender@example.com", &smtp.MailOptions{UTF8: true}) // If server doesn't support SMTPUTF8: // Error 504: "smtp: server does not support SMTPUTF8" ``` -------------------------------- ### Common Error Handling Patterns Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Examples for handling temporary errors, authentication failures, and message size limits. ```go // Pattern 1: Check for temporary errors err := client.Mail("sender@example.com", nil) if err != nil { var smtpErr *smtp.SMTPError if errors.As(err, &smtpErr) && smtpErr.Temporary() { // Implement exponential backoff retry } } // Pattern 2: Handle authentication errors err := client.Auth(mechanism) if err != nil { if err == smtp.ErrAuthFailed { log.Println("Invalid credentials") } else if err == smtp.ErrAuthRequired { log.Println("Authentication required") } } // Pattern 3: Handle size limit size, ok := client.MaxMessageSize() if ok && messageSize > size { log.Printf("Message too large: %d > %d", messageSize, size) } ``` -------------------------------- ### Initialize SMTPError with EnhancedCode Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Example of using EnhancedCode within an SMTPError structure. ```go err := &smtp.SMTPError{ Code: 550, EnhancedCode: smtp.EnhancedCode{5, 1, 1}, Message: "Bad destination mailbox", } ``` -------------------------------- ### Implement 451 Local Error in Backend Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of a backend session returning an error that triggers a 451 response. ```go type MyBackend struct{} func (b *MyBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { return nil, errors.New("database unavailable") // Server responds with 451 } ``` -------------------------------- ### Handle 421 Service Not Available Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of a client receiving a temporary service unavailable error during a NOOP command. ```go // Client code client, _ := smtp.Dial("mail.example.com:25") err := client.Noop() // May receive 421 if server is temporarily unavailable ``` -------------------------------- ### Handle 500 Syntax Error Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of server-side connection closure due to excessive protocol errors. ```go // Server code: Too many errors // After 3 protocol errors, connection is closed with 500 ``` -------------------------------- ### Handle SMTPError Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Example of checking SMTP error codes and handling temporary failures. ```go _, _, err := client.cmd(250, "MAIL FROM:<%s>", from) if err != nil { if smtpErr, ok := err.(*smtp.SMTPError); ok { log.Printf("Code: %d, Message: %s", smtpErr.Code, smtpErr.Message) if smtpErr.Temporary() { // Retry later } else { // Permanent failure } } } ``` -------------------------------- ### Enforce Authentication in Mail Session Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Example implementation of a Mail method that checks for session authentication status. ```go func (s *MySession) Mail(from string, opts *smtp.MailOptions) error { if !s.authenticated { return smtp.ErrAuthRequired } return nil } ``` -------------------------------- ### Report Status in LMTPData Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Example usage of SetStatus within an LMTPData implementation loop. ```go // In LMTPData method for _, rcpt := range recipients { err := deliverToMailbox(rcpt, message) status.SetStatus(rcpt, err) } ``` -------------------------------- ### Handle 501 Syntax Error in Parameters Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of a client receiving a 501 error due to invalid email address format. ```go client, _ := smtp.Dial("mail.example.com:25") err := client.Mail("invalid-address", nil) // May receive 501 for invalid address syntax ``` -------------------------------- ### Close DataCommand and handle errors Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/datacommand.md Examples of closing the DATA command and handling potential SMTP errors. ```go client, _ := smtp.DialStartTLS("mail.example.com:587", nil) defer client.Close() client.Mail("sender@example.com", nil) client.Rcpt("recipient@example.com", nil) cmd, _ := client.Data() fmt.Fprintf(cmd, "To: recipient@example.com\r\n\r\nHello\r\n") // Close and check for errors if err := cmd.Close(); err != nil { log.Printf("Message rejected: %v", err) } ``` ```go // Error handling with retry cmd, _ := client.Data() cmd.Write(largeMessage) if err := cmd.Close(); err != nil { var smtpErr *smtp.SMTPError if errors.As(err, &smtpErr) { if smtpErr.Code == 552 { log.Println("Message too large") } else if smtpErr.Temporary() { log.Println("Temporary error, can retry") } } } ``` -------------------------------- ### Create Client from existing connection Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Initializes a Client instance using an already established net.Conn. ```go // Create from an existing connection tcpAddr, _ := net.ResolveTCPAddr("tcp", "mail.example.com:25") conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { log.Fatal(err) } client := smtp.NewClient(conn) defer client.Close() ``` -------------------------------- ### Initialize a new SMTP server Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Create a server instance by providing a custom backend implementation that satisfies the Backend interface. ```go // Create basic server type MyBackend struct{} func (b *MyBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { return &MySession{}, nil } backend := &MyBackend{} server := smtp.NewServer(backend) server.Addr = ":25" server.Domain = "mail.example.com" ``` -------------------------------- ### Retrieve Client Hostname Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/conn.md Get the hostname provided by the client during the HELO/EHLO/LHLO handshake. ```go func (b *MyBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { hostname := c.Hostname() if hostname == "" { return nil, errors.New("invalid hostname") } return &MySession{hostname: hostname}, nil } ``` -------------------------------- ### Initialize SMTP Client with STARTTLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Creates a client from an existing connection and performs a STARTTLS upgrade. The connection is closed automatically if the upgrade fails. ```go // From existing connection with STARTTLS tcpAddr, _ := net.ResolveTCPAddr("tcp", "mail.example.com:25") conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { log.Fatal(err) } client, err := smtp.NewClientStartTLS(conn, nil) if err != nil { log.Fatal(err) } defer client.Close() ``` -------------------------------- ### Handle LMTPDataError Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Example of iterating over unwrapped errors from an LMTP DATA command. ```go cmd, _ := client.Data() _, _ = cmd.Write([]byte("message")) responses, err := cmd.CloseWithLMTPResponse() if err != nil { if lmtpErr, ok := err.(smtp.LMTPDataError); ok { for _, unwrappedErr := range lmtpErr.Unwrap() { log.Println(unwrappedErr) } } } ``` -------------------------------- ### Trigger ErrAuthUnknownMechanism in Auth Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of returning ErrAuthUnknownMechanism when an unsupported mechanism is requested. ```go func (s *MySession) Auth(mech string) (sasl.Server, error) { if mech != "PLAIN" { return nil, smtp.ErrAuthUnknownMechanism } return sasl.NewPlainServer(...), nil } ``` -------------------------------- ### Implement Backend Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/README.md Defines a custom backend structure and session initialization. ```go type MyBackend struct{} func (b *MyBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { return &MySession{}, nil } ``` -------------------------------- ### Trigger ErrAuthRequired in Mail Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of enforcing authentication before allowing the MAIL command. ```go type MySession struct { authenticated bool } func (s *MySession) Mail(from string, opts *smtp.MailOptions) error { if !s.authenticated { return smtp.ErrAuthRequired } return nil } ``` -------------------------------- ### Trigger ErrAuthFailed in Auth Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Example of returning ErrAuthFailed when authentication credentials do not match. ```go func (s *MySession) Auth(mech string) (sasl.Server, error) { return sasl.NewPlainServer(func(identity, username, password string) error { if password != "correctpassword" { return smtp.ErrAuthFailed } return nil }), nil } ``` -------------------------------- ### NewClientStartTLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Creates a new Client from an existing connection and immediately performs a STARTTLS upgrade. ```APIDOC ## func NewClientStartTLS(conn net.Conn, tlsConfig *tls.Config) (*Client, error) ### Description Creates a new Client from an existing connection and immediately performs STARTTLS upgrade. If STARTTLS fails, the connection is closed. ### Parameters - **conn** (net.Conn) - Required - An established network connection - **tlsConfig** (*tls.Config) - Optional - TLS configuration for upgrade ### Returns - **Client** (*Client) - A new SMTP client with TLS connection - **error** (error) - Error if STARTTLS fails or server doesn't support it ``` -------------------------------- ### Create Simple Backends with BackendFunc Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Simplifies backend implementation for basic use cases by providing a function that returns a session. ```go sessionFunc := func(c *smtp.Conn) (smtp.Session, error) { return &SimpleSession{}, nil } backend := smtp.BackendFunc(sessionFunc) server := smtp.NewServer(backend) ``` -------------------------------- ### Configure an email gateway server Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/package-overview.md Sets up an SMTP server instance with DSN support and message size limits. ```go s := smtp.NewServer(&GatewayBackend{}) s.Addr = "localhost:25" s.EnableDSN = true s.MaxMessageBytes = 10 * 1024 * 1024 s.ListenAndServe() ``` -------------------------------- ### Serve using a custom listener Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Accept connections on a pre-configured net.Listener for fine-grained network control. ```go // Custom listener for fine-grained control listener, err := net.Listen("tcp", "localhost:25") if err != nil { log.Fatal(err) } defer listener.Close() server := smtp.NewServer(backend) if err := server.Serve(listener); err != nil { log.Fatal(err) } ``` -------------------------------- ### Initialize LMTP Client Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Creates an LMTP client for local mail delivery using an existing connection. ```go // Create LMTP client for local delivery conn, err := net.Dial("unix", "/tmp/postfix-smtp") if err != nil { log.Fatal(err) } client := smtp.NewClientLMTP(conn) defer client.Close() ``` -------------------------------- ### Establish connection with custom TLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/package-overview.md Connects to an SMTP server using STARTTLS with a custom TLS configuration. ```go c, _ := smtp.DialStartTLS("smtp.example.com:587", &tls.Config{ ServerName: "smtp.example.com", }) defer c.Close() // Send message... ``` -------------------------------- ### Implement a Basic SMTP Server Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Defines a backend and session structure to handle incoming mail and recipients. Requires the go-smtp package. ```go import ( "io" "log" "time" "github.com/emersion/go-smtp" ) // Implement Backend type Backend struct{} func (b *Backend) NewSession(c *smtp.Conn) (smtp.Session, error) { return &Session{}, nil } // Implement Session type Session struct { from string rcpts []string } func (s *Session) Reset() { s.from = "" s.rcpts = nil } func (s *Session) Logout() error { return nil } func (s *Session) Mail(from string, opts *smtp.MailOptions) error { s.from = from log.Printf("Mail from: %s", from) return nil } func (s *Session) Rcpt(to string, opts *smtp.RcptOptions) error { s.rcpts = append(s.rcpts, to) log.Printf("Rcpt to: %s", to) return nil } func (s *Session) Data(r io.Reader) error { body, _ := io.ReadAll(r) log.Printf("Message: %s", string(body)) return nil } // Start server func main() { s := smtp.NewServer(&Backend{}) s.Addr = "localhost:1025" s.Domain = "localhost" s.WriteTimeout = 10 * time.Second s.ReadTimeout = 10 * time.Second s.MaxMessageBytes = 1024 * 1024 s.MaxRecipients = 50 log.Fatal(s.ListenAndServe()) } ``` -------------------------------- ### Connect to SMTP server with DialStartTLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Establishes a connection and upgrades it to TLS using the STARTTLS command. ```go // STARTTLS connection client, err := smtp.DialStartTLS("mail.example.com:587", nil) if err != nil { log.Fatal(err) } defer client.Close() ``` ```go // STARTTLS with custom configuration tlsConfig := &tls.Config{ InsecureSkipVerify: false, } client, err := smtp.DialStartTLS("mail.example.com:587", tlsConfig) if err != nil { log.Fatal(err) } defer client.Close() ``` -------------------------------- ### Send Email with STARTTLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Establishes a connection and upgrades to a secure TLS connection before sending. ```go c, _ := smtp.DialStartTLS("host:587", nil) defer c.Close() c.Auth(auth) c.SendMail(from, to, msg) ``` -------------------------------- ### Define Backend Interface Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Implement this interface to handle new client connections and session initialization. ```go type Backend interface { NewSession(c *Conn) (Session, error) } ``` -------------------------------- ### Implement BackendFunc Method Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Method signature for the BackendFunc adapter. ```go func (f BackendFunc) NewSession(c *Conn) (Session, error) ``` -------------------------------- ### NewServer(backend) Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Initializes a new SMTP server instance with the provided backend. ```APIDOC ## NewServer(backend) ### Description Creates a new SMTP server instance using the specified backend implementation. ### Parameters - **backend** (interface) - Required - The backend implementation to handle SMTP commands. ``` -------------------------------- ### Send Email (Minimal) Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/README.md Sends an email using the minimal configuration. ```go smtp.SendMail("host:25", nil, from, to, msg) ``` -------------------------------- ### Send Email Step-by-step Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Manual control over the SMTP transaction process for advanced use cases. ```go c, _ := smtp.Dial("host:25") defer c.Close() c.Mail(from, nil) c.Rcpt(to, nil) cmd, _ := c.Data() cmd.Write([]byte(msg)) cmd.Close() c.Quit() ``` -------------------------------- ### Implement LMTPData for Per-Recipient Status Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Example implementation of LMTPData that iterates through recipients and reports status using the StatusCollector. ```go type MyLMTPSession struct { from string rcpts []string } func (s *MyLMTPSession) LMTPData(r io.Reader, status smtp.StatusCollector) error { body, err := io.ReadAll(r) if err != nil { return err } // Report per-recipient status for _, to := range s.rcpts { if isValid(to) { status.SetStatus(to, nil) // Success } else { status.SetStatus(to, smtp.ErrAuthRequired) // Failure } } return nil } ``` -------------------------------- ### Detect server extensions Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Query the server for supported capabilities like STARTTLS or AUTH methods. ```go client, _ := smtp.Dial("mail.example.com:25") defer client.Close() // Check for specific extensions if ok, _ := client.Extension("STARTTLS"); ok { log.Println("Server supports STARTTLS") } if ok, _ := client.Extension("AUTH"); ok { log.Println("Server supports AUTH") } if client.SupportsAuth("PLAIN") { log.Println("PLAIN authentication is available") } ``` -------------------------------- ### Enable DELIVERBY Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Advertises support for delivery deadline parameters. ```go EnableDELIVERBY bool ``` -------------------------------- ### Send complete email via SMTP Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/datacommand.md A full implementation demonstrating connecting to a server, initiating a transaction, sending recipients, and transmitting message data. ```go package main import ( "fmt" "log" "github.com/emersion/go-smtp" ) func main() { // Connect to server client, err := smtp.Dial("mail.example.com:25") if err != nil { log.Fatal(err) } defer client.Close() // Start transaction from := "sender@example.com" if err := client.Mail(from, nil); err != nil { log.Fatal(err) } // Add recipients to := []string{"recipient1@example.com", "recipient2@example.com"} for _, addr := range to { if err := client.Rcpt(addr, nil); err != nil { log.Fatal(err) } } // Send message cmd, err := client.Data() if err != nil { log.Fatal(err) } // Write message msg := fmt.Sprintf( "From: %s\r\n"+ "To: %s\r\n"+ "Subject: Test\r\n"+ "\r\n"+ "This is a test message.\r\n", from, to[0], ) _, err = cmd.Write([]byte(msg)) if err != nil { log.Fatal(err) } // Close and get response resp, err := cmd.CloseWithResponse() if err != nil { log.Fatal(err) } log.Printf("Message sent: %s", resp.StatusText) // Disconnect if err := client.Quit(); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Enable BINARYMIME Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Advertises support for binary message content. ```go EnableBINARYMIME bool ``` -------------------------------- ### Send email with SendMail Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Use the package-level SendMail function for simple email delivery with STARTTLS and authentication. ```go import ( "log" "strings" "github.com/emersion/go-sasl" "github.com/emersion/go-smtp" ) // Prepare message from := "sender@example.com" to := []string{"recipient@example.com"} msg := strings.NewReader("To: recipient@example.com\r\n" + "Subject: Test\r\n" + "\r\n" + "This is the message body.\r\n") // Send with STARTTLS and authentication auth := sasl.NewPlainClient("", "user@example.com", "password") err := smtp.SendMail("mail.example.com:25", auth, from, to, msg) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Configure go-smtp Server with TLS Source: https://github.com/emersion/go-smtp/wiki/Server Sets up a go-smtp server with TLS enabled for secure authentication. Loads the certificate and key pair. ```go func main() { be := &Backend{} s := smtp.NewServer(be) s.Addr = ":1025" s.Domain = "localhost" s.ReadTimeout = 10 * time.Second s.WriteTimeout = 10 * time.Second s.MaxMessageBytes = 1024 * 1024 s.MaxRecipients = 50 // force TLS for auth s.AllowInsecureAuth = false // Load the certificate and key cer, err := tls.LoadX509KeyPair("server.crt", "server.key") if err != nil { log.Fatal(err) return } // Configure the TLS support s.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cer}} log.Println("Starting server at", s.Addr) if err := s.ListenAndServe(); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Enable REQUIRETLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Advertises support for the REQUIRETLS extension. ```go EnableREQUIRETLS bool ``` -------------------------------- ### Client Connection Patterns Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/package-overview.md Methods for establishing SMTP connections with varying levels of security. ```go client, _ := smtp.DialStartTLS("host:587", tlsConfig) ``` ```go client, _ := smtp.DialTLS("host:465", tlsConfig) ``` ```go client, _ := smtp.Dial("host:25") ``` -------------------------------- ### Implement Session Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/README.md Implements the required methods for an SMTP session. ```go func (s *MySession) Reset() {} func (s *MySession) Logout() error { return nil } func (s *MySession) Mail(from string, opts *smtp.MailOptions) error { return nil } func (s *MySession) Rcpt(to string, opts *smtp.RcptOptions) error { return nil } func (s *MySession) Data(r io.Reader) error { _, _ = io.ReadAll(r); return nil } ``` -------------------------------- ### Retrieve Server from Connection Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/conn.md Access the parent Server instance that created the connection. ```go func (b *MyBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { server := c.Server() log.Printf("Connection from %s, max message: %d bytes", c.Conn().RemoteAddr(), server.MaxMessageBytes) return &MySession{}, nil } ``` -------------------------------- ### Configure Server Timeouts Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Set read and write timeouts on the server instance to mitigate slow-client attacks. ```go server.ReadTimeout = 10 * time.Second server.WriteTimeout = 10 * time.Second ``` -------------------------------- ### Backend.NewSession Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Initializes a new session when a client connects and sends a greeting. ```APIDOC ## Backend.NewSession ### Description Called when a client connects and sends a greeting to the server. ### Signature `NewSession(c *Conn) (Session, error)` ``` -------------------------------- ### Implement Server Authentication Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Adds SASL authentication support to the session. Requires the go-sasl package. ```go import "github.com/emersion/go-sasl" type Session struct { authenticated bool } func (s *Session) AuthMechanisms() []string { return []string{sasl.Plain} } func (s *Session) Auth(mech string) (sasl.Server, error) { return sasl.NewPlainServer(func(identity, username, password string) error { if username != "testuser" || password != "testpass" { return smtp.ErrAuthFailed } s.authenticated = true return nil }), nil } func (s *Session) Mail(from string, opts *smtp.MailOptions) error { if !s.authenticated { return smtp.ErrAuthRequired } s.from = from return nil } ``` -------------------------------- ### Project File Structure Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/README.md Visual representation of the project directory layout. ```text output/ ├── README.md (this file) ├── package-overview.md (architecture & patterns) ├── quick-reference.md (type & function reference) ├── usage-guide.md (code examples) ├── types.md (type definitions) ├── errors.md (error codes & handling) └── api-reference/ ├── client.md (Client type) ├── server.md (Server type) ├── backend.md (Backend & Session) ├── conn.md (Conn type) └── datacommand.md (DataCommand type) ``` -------------------------------- ### Client Constructor Functions Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Functions to initialize a new SMTP or LMTP client. ```APIDOC ## NewClient(conn) Create SMTP client from net.Conn. ## NewClientStartTLS(conn, config) Create client with STARTTLS upgrade. ## NewClientLMTP(conn) Create LMTP client for local delivery. ``` -------------------------------- ### Set Backend Implementation Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Defines the backend used to handle mail operations. ```go Backend Backend ``` -------------------------------- ### Implement Mail Method Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Sets the sender address for the current message transaction. ```go func (s Session) Mail(from string, opts *MailOptions) error ``` ```go type MySession struct { from string } func (s *MySession) Mail(from string, opts *smtp.MailOptions) error { if from == "" && opts != nil && opts.Auth == nil { return &smtp.SMTPError{ Code: 550, Message: "Sender address required", } } s.from = from return nil } ``` -------------------------------- ### DSNReturn constants Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Available options for DSN return content. ```go const ( DSNReturnFull DSNReturn = "FULL" DSNReturnHeaders DSNReturn = "HDRS" ) ``` -------------------------------- ### Handle Authentication Failure (535) Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/errors.md Demonstrates an authentication attempt with incorrect credentials resulting in a 535 error. ```go client, _ := smtp.DialStartTLS("mail.example.com:587", nil) auth := sasl.NewPlainClient("", "user@example.com", "wrongpass") err := client.Auth(auth) // SMTP error 535: Authentication failed ``` -------------------------------- ### Server Lifecycle Methods Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/quick-reference.md Methods for managing the server's network connections and graceful shutdown. ```APIDOC ## Server Lifecycle Methods ### Methods - **ListenAndServe()** - Listens on the configured Addr and accepts incoming connections. - **ListenAndServeTLS()** - Listens on the configured Addr with TLS enabled and accepts incoming connections. - **Serve(listener)** - Accepts connections on a custom provided listener. - **Close()** - Force-closes all active connections. - **Shutdown(ctx)** - Performs a graceful shutdown, waiting for active connections to finish. ``` -------------------------------- ### TLS Configuration Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Defines the TLS settings required for encrypted connections and STARTTLS support. ```go TLSConfig *tls.Config ``` -------------------------------- ### Configure Server Debugging Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/README.md Sets up debug output for network activity and configures an error logger for the SMTP server. ```go server := smtp.NewServer(backend) server.Debug = os.Stdout // See all network activity server.ErrorLog = log.New(os.Stderr, "smtp: ", log.LstdFlags) ``` -------------------------------- ### Server TLS Configurations Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/package-overview.md Methods for configuring TLS on an SMTP server. ```go server.TLSConfig = tlsConfig // Advertises STARTTLS in EHLO // Clients can upgrade with STARTTLS command ``` ```go server.TLSConfig = tlsConfig server.ListenAndServeTLS() ``` -------------------------------- ### Implement Logging for SMTP Sessions Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Wraps an existing backend to log SMTP commands and session events using a decorator pattern. ```go type LoggingBackend struct { underlying smtp.Backend log *log.Logger } func (b *LoggingBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { sess, err := b.underlying.NewSession(c) if err != nil { b.log.Printf("NewSession error: %v", err) return nil, err } return &LoggingSession{ underlying: sess, log: b.log, conn: c, }, nil } type LoggingSession struct { underlying smtp.Session log *log.Logger conn *smtp.Conn } func (s *LoggingSession) Mail(from string, opts *smtp.MailOptions) error { s.log.Printf("[%s] MAIL FROM: <%s>", s.conn.Conn().RemoteAddr(), from) return s.underlying.Mail(from, opts) } func (s *LoggingSession) Rcpt(to string, opts *smtp.RcptOptions) error { s.log.Printf("[%s] RCPT TO: <%s>", s.conn.Conn().RemoteAddr(), to) return s.underlying.Rcpt(to, opts) } func (s *LoggingSession) Data(r io.Reader) error { s.log.Printf("[%s] DATA", s.conn.Conn().RemoteAddr()) return s.underlying.Data(r) } func (s *LoggingSession) Reset() { s.log.Printf("[%s] RSET", s.conn.Conn().RemoteAddr()) s.underlying.Reset() } func (s *LoggingSession) Logout() error { s.log.Printf("[%s] QUIT", s.conn.Conn().RemoteAddr()) return s.underlying.Logout() } ``` -------------------------------- ### RcptOptions Structure Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Contains parameters for the RCPT command, sent by the client and passed to Session.Rcpt. ```go type RcptOptions struct { Notify []DSNNotify OriginalRecipientType DSNAddressType OriginalRecipient string RequireRecipientValidSince time.Time DeliverBy *DeliverByOptions MTPriority *int } ``` -------------------------------- ### Write email content to DataCommand Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/datacommand.md Demonstrates writing headers and body content to an open DATA command stream. ```go client, _ := smtp.Dial("mail.example.com:25") client.Mail("sender@example.com", nil) client.Rcpt("recipient@example.com", nil) cmd, _ := client.Data() // Write headers _, err := cmd.Write([]byte("To: recipient@example.com\r\n")) if err != nil { log.Fatal(err) } _, err = cmd.Write([]byte("Subject: Test Email\r\n")) if err != nil { log.Fatal(err) } // Empty line separates headers from body _, err = cmd.Write([]byte("\r\n")) if err != nil { log.Fatal(err) } // Write body _, err = cmd.Write([]byte("This is the message body.\r\n")) if err != nil { log.Fatal(err) } ``` ```go // Using fmt.Fprintf for convenience cmd, _ := client.Data() defer cmd.Close() fmt.Fprintf(cmd, "To: user@example.com\r\n") fmt.Fprintf(cmd, "Subject: Hello\r\n") fmt.Fprintf(cmd, "\r\n") fmt.Fprintf(cmd, "Message body\r\n") ``` -------------------------------- ### Serve(l net.Listener) error Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Accepts incoming connections on a provided listener and handles them according to the SMTP protocol. ```APIDOC ## Serve(l net.Listener) error ### Description Accepts incoming connections on the provided Listener and handles them according to SMTP protocol. This method blocks until the server is closed. ### Parameters - **l** (net.Listener) - Required - Network listener for accepting connections ### Returns - **error** - Error from listening or connection handling ``` -------------------------------- ### Enable SMTPUTF8 Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Advertises support for UTF-8 encoded addresses. ```go EnableSMTPUTF8 bool ``` -------------------------------- ### func (c *Client) Hello(localName string) error Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Sends a HELO or EHLO command to the server with the specified local hostname. ```APIDOC ## func (c *Client) Hello(localName string) error ### Description Sends a HELO or EHLO command to the server with the specified local hostname. This method is only necessary when the client needs custom control over the hostname used. If Hello is called, it must be called before any other methods. ### Parameters - **localName** (string) - Required - Hostname to present to the server ### Returns - **error**: SMTPError if server returns an error ``` -------------------------------- ### NewClient Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Creates a new Client using an existing network connection. ```APIDOC ## func NewClient(conn net.Conn) *Client ### Description Creates a new Client using an existing network connection. The connection should be an established net.Conn. ### Parameters - **conn** (net.Conn) - Required - An established network connection ### Returns - **Client** (*Client) - A new SMTP client wrapping the connection ``` -------------------------------- ### Send Email (With Auth & TLS) Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/README.md Sends an email with authentication and TLS enabled. ```go c, _ := smtp.DialStartTLS("host:587", nil) defer c.Close() c.Auth(sasl.NewPlainClient("", user, pass)) c.SendMail(from, to, msg) ``` -------------------------------- ### MailOptions Structure Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Contains parameters for the MAIL command, sent by the client and passed to Session.Mail. ```go type MailOptions struct { Body BodyType Size int64 RequireTLS bool UTF8 bool Return DSNReturn EnvelopeID string Auth *string } ``` -------------------------------- ### Client Concurrency Patterns Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/package-overview.md Demonstrates the non-thread-safe nature of the Client type and the requirement for separate instances per goroutine. ```go // Wrong: sharing client across goroutines client, _ := smtp.Dial("host:25") go client.SendMail(from1, to1, msg1) // Race condition! go client.SendMail(from2, to2, msg2) // Right: separate clients for i := 0; i < 2; i++ { go func(idx int) { c, _ := smtp.Dial("host:25") defer c.Close() c.SendMail(from[idx], to[idx], msg[idx]) }(i) } ``` -------------------------------- ### BodyType constants Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Available MIME body type options. ```go const ( Body7Bit BodyType = "7BIT" Body8BitMIME BodyType = "8BITMIME" BodyBinaryMIME BodyType = "BINARYMIME" ) ``` -------------------------------- ### Client Authentication with SASL Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/package-overview.md Use the go-sasl package to authenticate an SMTP client. ```go import "github.com/emersion/go-sasl" auth := sasl.NewPlainClient("", "user@example.com", "password") client.Auth(auth) ``` -------------------------------- ### Check SMTP Extensions Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Use Extension to verify if a server supports specific features like STARTTLS or AUTH. The extension name is case-insensitive. ```go client, err := smtp.Dial("mail.example.com:25") if err != nil { log.Fatal(err) } defer client.Close() // Check for STARTTLS ok, _ := client.Extension("STARTTLS") if ok { log.Println("Server supports STARTTLS") } // Check for AUTH and get mechanisms ok, params := client.Extension("AUTH") if ok { log.Printf("AUTH mechanisms: %s", params) } ``` -------------------------------- ### Implement a Database-Backed SMTP Backend Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Uses a database transaction to store incoming email data during the DATA command phase. ```go type DBBackend struct { db *sql.DB } func (b *DBBackend) NewSession(c *smtp.Conn) (smtp.Session, error) { return &DBSession{ db: b.db, conn: c, }, nil } type DBSession struct { db *sql.DB conn *smtp.Conn from string rcpts []string txn *sql.Tx } func (s *DBSession) Mail(from string, opts *smtp.MailOptions) error { txn, err := s.db.Begin() if err != nil { return err } s.txn = txn s.from = from return nil } func (s *DBSession) Data(r io.Reader) error { body, _ := io.ReadAll(r) // Store in database _, err := s.txn.Exec( "INSERT INTO messages (sender, content) VALUES (?, ?)", s.from, string(body)) if err != nil { s.txn.Rollback() return err } return s.txn.Commit().Err() } ``` -------------------------------- ### Implement Logout Method Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Frees resources associated with the session upon connection closure or QUIT command. ```go func (s Session) Logout() error ``` ```go type MySession struct { db *sql.DB } func (s *MySession) Logout() error { // Clean up database connections if needed return nil } ``` -------------------------------- ### Define DeliverByOptions struct Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/types.md Structure for configuring delivery deadline constraints as defined in RFC 2852. ```go type DeliverByOptions struct { Time time.Duration Mode DeliverByMode Trace bool } ``` -------------------------------- ### Configure Server Address Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Sets the address for the server to listen on, supporting both TCP and Unix sockets. ```go Addr string ``` ```go server.Addr = "localhost:25" // TCP localhost server.Addr = ":25" // All interfaces server.Addr = "/tmp/postfix.sock" // Unix socket ``` -------------------------------- ### Enable MT-PRIORITY Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Advertises support for message priority levels. ```go EnableMTPRIORITY bool ``` -------------------------------- ### Connect to SMTP server with Dial Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Establishes a plaintext TCP connection to an SMTP server. ```go // Basic connection client, err := smtp.Dial("mail.example.com:25") if err != nil { log.Fatal(err) } defer client.Close() ``` ```go // With error handling and timeout awareness client, err := smtp.Dial("mail.example.com:25") if err != nil { // Handle network-level errors if opErr, ok := err.(*net.OpError); ok { log.Printf("Connection failed: %v", opErr) } return err } defer client.Close() ``` -------------------------------- ### Use UTF-8 and extended parameters Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/usage-guide.md Enable UTF-8 support in the Mail command using MailOptions. ```go // Send UTF-8 encoded message opts := &smtp.MailOptions{ UTF8: true, } client, _ := smtp.DialStartTLS("mail.example.com:587", nil) client.Mail("user@例え.jp", opts) client.Rcpt("recipient@example.com", nil) // ... send message ... ``` -------------------------------- ### Connect to SMTP server with DialTLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Establishes an implicit TLS connection to an SMTP server. ```go // Basic TLS connection client, err := smtp.DialTLS("mail.example.com:465", nil) if err != nil { log.Fatal(err) } defer client.Close() ``` ```go // With custom TLS configuration tlsConfig := &tls.Config{ ServerName: "mail.example.com", } client, err := smtp.DialTLS("mail.example.com:465", tlsConfig) if err != nil { log.Fatal(err) } defer client.Close() ``` -------------------------------- ### Enable DSN Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/server.md Advertises support for Delivery Status Notifications. ```go EnableDSN bool ``` -------------------------------- ### DialStartTLS Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Creates a new Client connected to an SMTP server via STARTTLS (explicit TLS upgrade). ```APIDOC ## func DialStartTLS(addr string, tlsConfig *tls.Config) (*Client, error) ### Description Creates a new Client connected to an SMTP server via STARTTLS (explicit TLS upgrade) at the given address. The connection starts plaintext and is upgraded to TLS using the STARTTLS command. ### Parameters - **addr** (string) - Required - TCP network address with port (e.g., "mail.example.com:587") - **tlsConfig** (*tls.Config) - Optional - TLS configuration for upgrade ### Returns - **Client** (*Client) - A new SMTP client with TLS upgraded connection - **error** (error) - Error if connection fails or server doesn't support STARTTLS ``` -------------------------------- ### Verify Connection with Noop Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Noop sends a NOOP command to verify that the connection to the server remains active and healthy. ```go client, err := smtp.Dial("mail.example.com:25") if err != nil { log.Fatal(err) } defer client.Close() // Check connection health err = client.Noop() if err != nil { log.Fatal("Connection to server failed:", err) } ``` -------------------------------- ### Verify Authentication Mechanisms Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md SupportsAuth checks if the server supports a specific authentication mechanism, such as PLAIN or LOGIN. ```go client, err := smtp.Dial("mail.example.com:25") if err != nil { log.Fatal(err) } defer client.Close() if client.SupportsAuth("PLAIN") { log.Println("PLAIN authentication is supported") } ``` -------------------------------- ### BackendFunc Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md An adapter that allows an ordinary function to be used as a Backend implementation. ```APIDOC ## BackendFunc ### Description BackendFunc is an adapter that allows an ordinary function to be used as a Backend. It calls the underlying function with the connection to return a Session. ### Signature func(c *Conn) (Session, error) ``` -------------------------------- ### Initiate Mail Transaction with Mail Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/client.md Initiates a mail transaction by issuing a MAIL command. Must be followed by one or more Rcpt calls. ```go client, err := smtp.Dial("mail.example.com:25") if err != nil { log.Fatal(err) } defer client.Close() // Simple mail from err = client.Mail("sender@example.com", nil) if err != nil { log.Fatal(err) } // With options opts := &smtp.MailOptions{ Size: 1024, UTF8: true, } err = client.Mail("sender@example.com", opts) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Implement Data Method Source: https://github.com/emersion/go-smtp/blob/master/_autodocs/api-reference/backend.md Processes the message content provided via an io.Reader. ```go func (s Session) Data(r io.Reader) error ``` ```go type MySession struct { from string rcpts []string } func (s *MySession) Data(r io.Reader) error { // Read the message body, err := io.ReadAll(r) if err != nil { return err } log.Printf("Message from %s to %v: %d bytes", s.from, s.rcpts, len(body)) // Process/store the message return nil } ```