Introduction
As Go developers, you usually work deep on the backend. When it’s time to send notifications via email, sending encoded HTML to users via SMTP can feel pretty foreign. It can be tempting to stick with only in-app notifications, but that’s not ideal for user retention.
In this tutorial, you will be provided with three different methods for sending emails with Golang: directly with the core SMTP package or Gomail, API requests to third-party mail services like Amazon SES or Mailgun, and using a multi-channel messaging abstraction service like Courier.
Email-sending fundamentals in Golang
Before setting up your server or third-party API server to send emails, let’s discuss a few fundamentals.
Sanitizing email user inputs
As you receive personal information (like contact information) from users on your platform, it’s essential to sanitize the data before using it. To help prevent malicious attacks on your app, you’ll want to remove HTML entities, slashes, and tags. You’ll want to perform this sanitization on a trusted system (your backend) rather than in the frontend UI, as such frontend checks can be disabled by malicious actors.
Sending plain text emails vs. HTML formatted emails
The email notification you plan to send will determine whether you need HTML or plain text. HTML supports emails that include media, external links, branding, structure, and style. One major drawback to HTML emails is that they are apt to get caught in your users’ spam boxes. Or worse, their style can be stripped due to antivirus software. HTML emails are more prone to phishing or malware attacks than the alternative, plain text emails.
Plain text is precisely what it implies: just words on a page. And sometimes, simple text is all you need to convey your message. This email form is typically used for correspondence (like when your sales team is having a back-and-forth conversation with a potential customer). A couple of significant pros are: plain text emails load quickly, and they open easily on every type of device.
Sending email attachments in Golang
When you want to share images or documents (or anything externally), you’ll need to attach them to your email using a third-party package like Gomail:
1
2
msg := gomail.NewMessage()
msg.Attach("/home/User/cat.jpg")
Transactional vs. marketing emails with Golang
Transactional and marketing emails serve two different purposes:
Transactional emails are triggered by an action taken within the app and sent to one user at a time. The email your user receives could be a payment receipt, an abandoned cart, a welcome email, a password reset, or something else.
Marketing emails, on the other hand, are usually sent out in large quantities. These emails notify your user about upcoming product launches, sales, or other types of information you want to share. Keep in mind that these types of transactions are subject to local laws. When sending emails directly from our backend, you’re unlikely to want to send bulk emails very often.
You may encounter a third category of email, a delayed job send. This isn’t a marketing email: it’s not the same information for every user. It’s an update sent to many users due to a delayed job or background process. One example might be a two-week warning that a user’s password is about to expire. Often these are the most aggravating to get working correctly since a single email works just fine in tests. However, trying to send out hundreds of emails typically fails due to rate-limiting from email servers. A system like Courier acts as an abstraction layer between your email service and can make these challenges much more effortless.
Three options to send emails using Golang
SMTP
When you send and receive emails, the server most likely uses SMTP to deliver them.
Using Golang’s SMTP package gives you immediate access to the Go installation.
Package SMTP
Using the Golang SMTP package, you can configure your backend service to send emails using any SMTP server you want.
In this demo, you’ll be using the Google Gmail SMTP server.
Before you begin, you’ll need a Google account and you’ll have to enable access to less secure apps. You’ll also need a password if you have two-step authentication turned on. Obviously, this isn’t a great way to run in production. Even in your experiments, you should set environmental variables for these values and load them with os.Getenv
.
In the code below, the “Plain Auth” function uses four arguments: identity, username, password, and host. The identity should be left to an empty string.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main
import "net/smtp"
func main() {
from := "<paste your gmail account here>"
password := "<paste Google password or app password here>"
toEmailAddress := "<paste the email address you want to send to>"
to := []string{toEmailAddress}
host := "smtp.gmail.com"
port := "587"
address := host + ":" + port
subject := "Subject: This is the subject of the mail\n"
body := "This is the body of the mail"
message := []byte(subject + body)
auth := smtp.PlainAuth("", from, password, host)
err := smtp.SendMail(address, auth, from, to, message)
if err != nil {
panic(err)
}
}
Here, the []byte
value for the message is just plain text, but the SMTP package can encode HTML for the body. Note that both the Subject:
and \n
in the subject value are required to be read correctly by the email service.
The SMTP package is ideal for when you need to send very basic emails that don’t require a lot of configuration.
Package Gomail
The default package SMTP can be limiting. For example, you can’t add an attachment to your email. Gomail offers a comprehensive range of functions like HTML templates, embedded images, and automatic encoding. To use Gomail, you’ll need Go 1.2 or newer. You can install it using the following command:
1
$ go get gopkg.in/gomail.v2
NewMessage
creates a new message in the code below and the SetHeader
function sets the headers. The SetBody
function is used for the message itself.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main
import (
gomail "gopkg.in/gomail.v2"
)
func main() {
msg := gomail.NewMessage()
msg.SetHeader("From", "<paste your gmail account here>")
msg.SetHeader("To", "<paste the email address you want to send to>")
msg.SetHeader("Subject", "<paste the subject of the mail>")
msg.SetBody("text/html", "<b>This is the body of the mail</b>")
msg.Attach("/home/User/cat.jpg")
n := gomail.NewDialer("smtp.gmail.com", 587, "<paste your gmail account here>", "<paste Google password or app password here>")
// Send the email
if err := n.DialAndSend(msg); err != nil {
panic(err)
}
}
Because you’re using a third-party package, the “Attach” function attaches external files to the email. The “NewDialer” function and “DialAndSend” open up an SMTP server connection and send the email.
Third-party email API services
Third-party email API services like SendGrid, Mailgun, and Amazon Simple Email Service have dedicated platforms that allow you to efficiently send mass emails.
Using an SMTP server, you can programmatically send emails. Still, third-party API servers allow you to send tens of thousands of emails daily that are scalable, powerful, and offer backend analytics. In most cases, after signing up for an account, you’ll have the choice of using a web API or SMTP.
Amazon - Simple Email Service (SES) Amazon Simple Email Service helps you send emails inexpensively. One significant disadvantage is that AWS in general and SES are really intended for people who use them all the time. Despite the “simple” in the name, over time you’ll find that you really need to be an expert on SES to use it without running into problems.
With the Amazon SES free tier, depending on where your app is hosted, you can send up to 62,000 emails per month.
To start with Amazon SES and integrate with Go, first sign up to add and verify your domain and emails. If you want to use SMTP, retrieve your credentials and replace them in Gomail in your Golang app.
You also have the option to use the Amazon SES console or [Amazon SES API](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/examples-send-using-sdk.html0. Consider using Amazon SES if you want an inexpensive platform or if you’re hosting your web app on AWS.
Mailgun Mailgun is another third-party service that helps send automated emails. One of its greatest strengths is its ability to provide more in-depth analytics compared with Amazon SES. It also includes an email verification service that helps you eliminate invalid email addresses and reduces bounce rate.
Mailgun is not as cheap as Amazon SES, but it's easier to get started and has better documentation.
Note: It’s important to send a test email for any email service so you know if your emails are landing in spam, promotions, or inbox folders.
Using a multi-channel notification system
You may sometimes wish to send notifications to various channels, including email, push notifications, and SMS. A multi-channel notification system is designed to do just that.
Courier is a multi-channel notification system that can help you easily design and send notifications. With one API, you can send a notification using multiple languages.
To integrate Courier with Go, create an account and complete the onboarding process, which will walk you through creating and sending your first notification.
1. Create a notification
Select the Designer on the left hand menu, and then select the 'Create Notification' button. You can edit the title once you have created it.
2. Add channels
Next, you need to add the notification channels you want to use with this notification. You can start with one channel, such as email, and add others later. For example, to send messages via Gmail you can click on and login via Gmail, and start sending emails. To send an SMS, you can add your Twilio authentication tokens.
Learn more about how to integrate your preferred provider >
3. Create notification content
After you've selected at least one channel, you can begin adding content to your notification using content blocks. Types of content blocks include text, images, buttons, and other options. You can also input dynamic variables, which can be populated when sending using single curly brackets {}.
Once you've built the content in one channel, simply open another and pull in the blocks you've already created from the content library. Courier dynamically adjusts content blocks to match every channel's technical specifications. You can use the toolbar to add new, reusable content blocks in any channel.
4. Publish the notification
To make your changes live, select the 'Publish Changes' button in the top right corner.
5. Test the notification
To test the notification, you will need to create a test user profile. Courier will direct you to creating a new test profile when you click on “Preview”. If your user is stored in your user management interface, you can directly reference the user-id, or list_id to reference a predetermined list of multiple users.
We recommend using test user data here while you are testing the notification.
1
2
3
4
5
6
7
8
9
10
{
"courier": {},
"data": {
"name": "Lucy"
},
"profile": {
"user_id": "USER_ID"
},
"override": {}
}
Otherwise, you can add in the user’s email
address for the email channel and phone_number
for the SMS channel.
1
2
3
4
5
6
7
8
9
10
11
{
"courier": {},
"data": {
"name": "Lucy"
},
"profile": {
"email": "example@email.com",
"phone_number": "555-555-5555"
},
"override": {}
}
This is what the preview looks like once we have added the user profile and data to the test event:
You can test send the notification within the UI and check the datalog to ensure that it is being sent successfully.
6. Integrate with Go
With the Courier Go SDK, you can send notifications straight from your app code. While our notifications API lets you send notifications with a POST request, the SDK makes it even easier without having to directly manage requests.
Download the package
1
$ go get -u github.com/trycourier/courier-go/v2
The following code will send an idempotent message using the SendMessageWithOptions method as shown below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main
import (
"context"
"log"
"github.com/trycourier/courier-go/v2"
)
func main() {
client := courier.CreateClient("<YOUR_AUTH_TOKEN>", nil)
requestID, err := client.SendMessage(
context.Background(),
courier.SendMessageRequestBody{
Message: map[string]interface{}{
"to": map[string]string{
"user_id": "<USER_ID>",
},
"template": "<NOTIFICATION_TEMPLATE_ID>",
},
},
)
if err != nil {
log.Fatalln(err)
}
log.Println(requestID)
}
7. Replace the variables
You can find the notification template ID in the settings of your notification. Replace <COURIER_TEMPLATE>
in the message object with this string.
Replace <YOUR_AUTH_TOKEN>
with your Courier auth token. To get your auth tokens, navigate to API Keys under your Settings, as shown in the screenshot below:
Check which environment you are sending from (top right of the Courier studio). If you’re in the Production environment, use the first Production Key. If you are in the Test environment, use the Test Key.
8. Send your message
Run your program to send messages to your users.
If you run into any errors, checking the datalog will provide you with more context to determine how to resolve it. Checkout the Send API Reference to learn about more parameters.
You can also use Amazon SES, Mailgun, SendGrid, or other providers to programmatically send emails with Courier. You can visit the website for a complete reference of the email integrations that Courier supports.
Conclusion
This guide covered three ways of sending emails with Golang using the package SMTP and Gomail.
To get started quickly with an SMTP server, you’ll want to use the Golang app. Go allows you to send 500 emails every 24 hours.
If you want to send mass emails, try Amazon SES or Mailgun. As third-party services, they can send emails for medium to large-scale projects.
With Amazon SES, you can send thousands of emails daily from a trusted platform, and this option includes analytic capabilities. Mailgun, while more expensive, offers additional analytical features and email verification services that may justify the price tag depending on what you’re looking for.
Using a notification system like Courier, you can integrate with Amazon SES, Mailgun, or SendGrid to send emails using a simple API. To send notifications quickly, sign up with Courier today.
Further reading
Learn about Golang, the Go programming language for highly efficient code.