Golang Sendmail: Sending mail using net/smtp package

SMTP is a mechanism of sending mail from one end to other. It works in the application layer of TCP/IP model. Sometimes TLS or SSL is used to make a secure connection between the end systems.

When SMTP client has a message to transmit, it establishes a two way transmission channel to the SMTP server. After the connection is established, the client initiates a mail transaction. The transaction consists of a series of command to the server. The server responds to each message with a reply. The reply indicates whether the command was accepted or additional data is required or indication of any error.

This is how a plain SMTP interaction is done(source wikipedia).

SMTP transports a mail object and a mail object contains an envelope and mail content. SMTP envelop contains

  1. creation of a session and client initiation: the server sends a greeting message and client sends identity. (EHLO)
  2. Mail transactions: It consists of MAIL FROM command, RCPT TO command and DATA command.

DATA command indicates, the envelop ended and the client will send the mail content.

The net/smtp package provides functions for all ESMTP commands.

For CC field in the mail, SMTP recommends adding CC receiver details in the content of the mail and sending the same copy to all receiver. For BCC, the details are not added to the content, but mail is sent.

Golang net/smtp package provides function for each of these commands.

func Dial(addr string) (*Client, error) 
func NewClient(conn net.Conn, host string) (*Client, error)
func (c *Client) Hello(localName string) error

All first two functions return a client. The third method should be used to specify a specific host name. The programmer doesn’t need worry about EHLO command, because the library handles that.

func (c *Client) Mail(from string) error

Mail method sends a MAIL FROM command.

func (c *Client) Rcpt(to string) error

The Rcpt method sends a RCPT TO command.

func (c *Client) Data() (io.WriteCloser, error)

The Data() method sends a DATA command to the server. It returns an io writer object. The Mail content to be sent should be written in this object.

func (c *Client) Close() error

Finally, close methods sends a QUIT command .

Here is a sample example.

Don’t try this. This doesn’t work for Gmail. Gmail needs password for login and SSL/TLS for end-to-end security.

The original SMTP implementation didn’t have any security. But some security feature was added eventually. All SMTP servers maintain a database of sender identity and the FROM MAIL address mapping. So, when a user sends a mail, the mail id mentioned in FROM MAIL command should be mapped to the identity of the user. All SMTP servers also need clients to provide some kind of end to end security.

The first part of security is to use TLS, instead of TCP. The NewClient() method takes a net.conn object and reuses that connection to create a SMTP client object.

When the client sends EHLO command, the server replies with a list of service extension it supports. That service extension contains lists authentication mechanism it supports. This is a typical response from SMTP server.

EHLO localhost
250-smtp.gmail.com at your service, []
250-SIZE 35882577

The client needs to send AUTH data after EHLO command and before MAIL FROM command.

In our example, we will use PLAIN auth.

In PLAIN auth, the client sends username and password tuple to the server.

After that we send, rest of the commads as explained before.

The complete code sample can be found here,

For CC and BCC the same mail needs to be sent to individual recipients. The mail content will be same for all mails sent. BCC details are not provided inside mail content.

Here is sample code for CC and BCC.

Thanks for reading !!

C++11/14, Qt, Juce