You might often need to send emails to many accounts using programs for authentication and many other purposes.

The SMTP protocol defines standards that allow email communication across mail servers and mail transfer agents, while the IMAP protocol is for receiving emails.

Go provides functionality for email-related activities defined by the RFC in the net/smtp package, which also contains 8BITMIME, AUTH, and STARTTLS extensions.

The code used in this project is available in a GitHub Repository and is free for you to use under the MIT license.

How to Send Emails in Go Using the Net/SMTP Package

The net/smtp package is part of the Go standard library, so you don't need to install any external package. You only need to import the package before using it.

        import (
    "net/smtp"
    "log"
    "crypto/tls"
    "fmt"
)

You will also need to import the log package to log errors to the console and the crypto/tls package to configure a safe connection.

Once you've imported the net/smtp package, you should write a SendMail() function to send the mail and then call the function in the main function.

        func main() {
    fmt.Print(SendMail())
}
func SendMail() string {
    // Add code here
}

The SendMail() function would contain the code that sends the mail to recipients.

How Sending Emails Work

The SMTP protocol defines the parameters that every mail needs to have. These parameters are the sender and receiver mail addresses, a port on which the mail is sent, a host server, and a message.

The parameters stated above are important for sending emails.

In this tutorial, you'll learn to send Yahoo emails. However, the process is the same for whatever Mail Server Provider (MSP) you use.

Since you're using Yahoo Mail, log in to your Yahoo Mail account, head on to Account Info, and click the Account Security tab. Then generate an app password. You'll need to name the app, and then Yahoo Mail will create a password for the app, and you can use the password in your code along with your mail address.

Yahoo mail generate password user interace

In the SendMail() function, you’ll declare three variables; a variable that holds the string of your email, one that holds your email password, and a string that holds the email address you are sending messages to.

        from := "yourMail@gmail.com"
password := "aSecurePasswordHere"
to := "anemail@gmail.com"

You can use a slice and loop through the elements if you intend to send them to multiple recipients.

Getting and Setting the Email Host and Port

The SMTP protocol uses the host and port numbers to identify the email source. This is where your MSP comes in. You need to know the host and port number your MSP allows you to use.

Check this resource for a list of MSP hosts and port numbers if you use public emails like Gmail, Yahoo, or Outlook. Google has turned off “less secure apps” for Gmail; you might want to secure your application if you’re using Gmail.

Once you’ve got the port number and host address, assign them to variables like this:

        host := "smtp.mail.yahoo.com"
port := "465"

The host and port numbers above are from Yahoo Mail for use on regular accounts. The server is hosted at smtp.mail.yahoo.com, and you’re allowed to use port 465 to send Emails.

Declaring the Contents of the Email

The next step is to declare the contents of the mail as variables. The subject and the body make up the message.

        subject := "Hey, I'm Just Checking On You."
body := "Hope you're doing okay! How are you doing today. "

The subject variable is the subject of the email; the body variable is the body of the email you’re sending.

Setting the Email Headers

You’ll need to make a map of strings to denote the headers of the email.

        headers := make(map[string]string)
headers["From"] = from
headers["To"] = to
headers["Subject"] = subject
message := ""
for k, v := range headers {
    message += fmt.Sprintf("%s: %s\r", k, v)
}
message += "\r" + body

First, you create a map of string keys and values and set the headers of your address, the recipient’s address, and the subject, as shown above. Using a range for-loop on the headers map, a message variable is declared to contain the headers and the message using string formatting.

Authenticating the Email

The email needs authentication to verify the source. The smtp package provides functionality for email authentication using the PlainAuth. The PlainAuth method takes in the identity, sender’s Email, password, and host as parameters and returns an Auth object you’ll use to send the email.

        authenticate := smtp.PlainAuth("", from, password, host)

The identity is your username, which can be left blank, as seen in this case.

Creating a Connection for the Email

Some mail service providers require you to send the email via a connection. In this article, we’ll be making a TCP connection to the server with TLS configurations.

        tlsConfig := &tls.Config{
    InsecureSkipVerify: true,
    ServerName: host,
}

In the code above, you made a TLS configuration by referencing the Config struct where InsecureSkipVerify was set to true, and the server name was assigned to the host variable.

You must create a TCP connection using the Dial method of the tls package. The dial method takes in the connection type (TCP), in this case, the server address and the TLS connection configurations.

        
connection, err := tls.Dial("tcp", serverAddress, tlsConfig) err != nil {
    log.Panic(err)
}

In the code above, you made a TCP connection and handled errors; you’ll have instantiated a new smtp package using the NewClient method of the net/smtp package. The NewClient method takes in a connection and host, respectively.

        smtpClient, err := smtp.NewClient(connection, host)
if err != nil {
    log.Panic(err)
}

Now that you’ve created an smtp client instance, you have to set the parameters of the smtpClient and handle errors.

        if err = smtpClient.Auth(authenticate); err != nil {
    log.Panic(err)
}
if err = smtpClient.Mail(from); err != nil {
    log.Panic(err)
}

if err = smtpClient.Rcpt(headers["To"]); err != nil {
    log.Panic(err)
}

In the example above, you passed the authentication, sender address, and recipient address parameters to their respective methods and handled errors.

Finally, you have to write to the connection instance, and you can do that by creating a writer using the Data method of your smtp client instance.

        writer, err := smtpClient.Data()
if err != nil {
    log.Panic(err)
}

_, err = writer.Write([]byte(message))
if err != nil {
    log.Panic(err)
}

After creating a writer, you write a byte slice of the message using the Write method as in the example above.

        err = writer.Close()
if err != nil {
    log.Panic(err)
}
err = smtpClient.Quit()
if err != nil {
    return
}

return "Successful, the mail was sent!"

Close the writer and quit the smtp client connection instance using the above code. The SendMail() function returns a success message, as shown above.

On calling the SendMail() function in the main function, you should get the success message logged to your console, and the email` sent to your recipient.

Proof that the email was sent successfully

There's More to the Net Package

The net package contains many packages for network-related functionalities and the smtp package is just one of them. You can also use the TCP and HTTP packages for networking-related development.

You might find the net/smtp package overwhelming if you're not a backend developer. There are many other alternatives for sending emails quickly with fewer lines of code. You can check out email marketing companies like SendGrid, Twilio, and MailChimp and newsletter services like Substack and Revue that allow you to send emails to many users without stress.