How to create a basic SMTP server with Go

The Simple Mail Transfer Protocol (SMTP) is essential for sending emails. Implementing a custom SMTP server can be useful to better understand how the protocol works and to develop tailored applications. In this article, we will explore how to create a basic SMTP server using the Go programming language.

Go provides a rich standard library, but for an SMTP server, we will use an external library called go-smtp, which simplifies the management of an SMTP server.


go get github.com/emersion/go-smtp

Start by importing Go's standard packages and the go-smtp library:


package main

import (
	"fmt"
	"log"
	"net"
	"github.com/emersion/go-smtp"
)

The handler is a structure that implements the smtp.Backend interface. This is where you define how to handle received messages.


type EmailHandler struct {}

func (e *EmailHandler) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) {
	return nil, smtp.ErrAuthUnsupported
}

func (e *EmailHandler) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) {
	return &Session{}, nil
}

// SMTP session implementation
type Session struct {}

func (s *Session) Mail(from string, opts smtp.MailOptions) error {
	log.Printf("Email received from: %s", from)
	return nil
}

func (s *Session) Rcpt(to string) error {
	log.Printf("Recipient: %s", to)
	return nil
}

func (s *Session) Data(r io.Reader) error {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r)
	log.Printf("Email content: %s", buf.String())
	return nil
}

func (s *Session) Reset() {}
func (s *Session) Logout() error { return nil }

func (e *EmailHandler) NewSession(state *smtp.ConnectionState) (smtp.Session, error) {
	return &Session{}, nil
}

Once the handler is defined, we can configure and start the SMTP server.


func main() {
	handler := &EmailHandler{}

	// Configure the server
	server := smtp.NewServer(handler)
	server.Addr = ":2525"
	server.Domain = "localhost"
	server.AllowInsecureAuth = true

	// Start the server
	log.Printf("Starting SMTP server on port %s", server.Addr)
	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}

Conclusion

We have created a basic SMTP server with Go, which can receive emails and manage senders and recipients. This server serves as a foundation on which more advanced features can be built, such as authentication, TLS support, or integration with a storage system. Deepening your understanding of the SMTP protocol and the go-smtp library will allow you to develop customized solutions for your needs.

Back to top