golang

Golang Send Email

The SMTP protocol is one of the building blocks of modern internet. The protocol acts as the standard for e-mail transmissions. It comprises a mail server and a mail client to facilitate the transfer of emails.

In this guide, we will discuss how you can send emails using the SMTP package in Go. For testing, we will use a locally hosted SMTP server using MailSlurper.

Golang SMTP

The SMTP package is a sub-package of the Golang net package. It implements high-level functionalities for working with SMTP protocol.

Let’s learn how to send email using the SMTP package.

The SMTP package provides a SendMail() method that allows you to send email to the specified address.

The function syntax is as shown:

func SendMail(addr string, a Auth, from string, to []string, msg []byte) error

The function accepts the address of the SMTP server as a string, an authentication mechanism, email address to send from, the email address to send to, and the email message as the parameters.

The email message should start with the header, a blank line, and the email body. You should end each line of the message with CRLF characters, allowing compliance with RFC 822 email style.

The following code shows a simple example of using the SendMail function to send an email.

package main
import (
    "fmt"
    "log"
    "net/smtp"
)

const (
    USERNAME = "linuxhint"
    PASSWD   = "password"
    HOST     = "localhost"
)

func main() {
    from := "[email protected]"
    to := []string{
        "[email protected]",
    }
    msg := []byte("From: [email protected]\r\n" +
        "To: [email protected]" +
        "Subject: Golang testing mail\r\n" +
        "Email Body: Welcome to Go!\r\n")

    auth := smtp.PlainAuth("", USERNAME, PASSWD, HOST)
    err := smtp.SendMail(HOST+":25", auth, from, to, msg)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Mail sent successfully!")
}

In the example above, we start by importing the required packages. We then specify the required variables. In our example, we set the username, password, and the host.

In the main function, we set the sender of the email and the receiver using the from and to variables, respectively.

Next comes the email body, we use RFC 822 style to construct the message. Note that each line is separated with CRLF characters.

Next, we build the authentication using the PlainAuth method. The function takes the identity, username, password and host and gears a plain auth mechanism with the server. The function then returns to an auth object.

Finally, we send the email using the SendMail function passing the address, auth object, sender, recipient and the message as the arguments.

MailSlurper Auth Method

If you run the code above on MailSlurper, the server will return an error as below and close the connection.

$ go run emails.go
2022/02/02 02:52:39 smtp: server doesn't support AUTH
exit status 1

You can solve this by using a custom SendMail function. An example code is as shown below:

package main

import (
    "encoding/base64"
    "fmt"
    "log"
    "net/smtp"
    "strings"
)

const (
    USERNAME = "linuxhint"
    PASSWD   = "password"
    HOST     = "localhost"
)

func main() {
    from := "[email protected]"
    to := []string{
        "[email protected]",
    }
    msg := []byte("Email Body: Welcome to Go!\r\n")
    err := SendMail(HOST+":2500", from, "Golang testing email", string(msg), to)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Mail Sent Successfully!")

}
func SendMail(addr, from, subject, body string, to []string) error {
    r := strings.NewReplacer("\r\n", "", "\r", "", "\n", "", "%0a", "", "%0d", "")

    c, err := smtp.Dial(addr)
    if err != nil {
        return err
    }
    defer c.Close()
    if err = c.Mail(r.Replace(from)); err != nil {
        return err
    }
    for i := range to {
        to[i] = r.Replace(to[i])
        if err = c.Rcpt(to[i]); err != nil {
            return err
        }
    }

    w, err := c.Data()
    if err != nil {
        return err
    }

    msg := "To: " + strings.Join(to, ",") + "\r\n" +
        "From: " + from + "\r\n" +
        "Subject: " + subject + "\r\n" +
        "Content-Type: text/html; charset="UTF-8"\r\n" +
        "Content-Transfer-Encoding: base64\r\n" +
        "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))

    _, err = w.Write([]byte(msg))
    if err != nil {
        return err
    }
    err = w.Close()
    if err != nil {
        return err
    }
    return c.Quit()
}

Golang Send Mail – Carbon Copy

You can also send emails to multiple users using carbon copy and blind carbon copy. CC recipients will be visible to all.

We can do this using the code as below:

package main
import (
    "fmt"
    "log"
    "net/smtp"
    "strings"
)

type Mail struct {
    Sender  string
    To      []string
    CC      []string
    Bcc     []string
    Subject string
    Body    string
}

func main() {
    sender := "[email protected]"
    to := []string{
        "[email protected]",
        "[email protected]",
        "[email protected]",
    }
    cc := []string{
        "[email protected]",
        "[email protected]",
    }
    username := "linuxhint"
    passwd := "password"
    host := "localhost"

    subject := "Golang Mail Test"
    body := "Message body"

    req := Mail{
        Sender:  sender,
        To:      to,
        CC:      cc,
        Subject: subject,
        Body:    body,
    }
    msg := ComposeMsg(req)
    auth := smtp.PlainAuth("", username, passwd, host)
    err := smtp.SendMail(host+":2500", auth, sender, to, []byte(msg))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Message Sent successfully!")
}

// construct message based on the cc
func ComposeMsg(mail Mail) string {
    // empty string
    msg := ""
    // set sender
    msg += fmt.Sprintf("From: %s\r\n", mail.Sender)
    // if more than 1 recipient
    if len(mail.To) > 0 {
        msg += fmt.Sprintf("Cc: %s\r\n", strings.Join(mail.CC, ";"))
    }
    // add subject
    msg += fmt.Sprintf("Subject: %s\r\n", mail.Subject)
    // add mail body
    msg += fmt.Sprintf("Body: %s\r\n", mail.Body)
    return msg
}

The above code will send the emails to the specified recipients using the SMTP protocol.

Closing

In this guide, we explored the basics of using the SMTP package in Go to send emails to one or more users. Check the documentation to learn more.

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list