Introduction
Have you ever wondered how newsletters from different companies and organisations work? Some companies use platforms like Mailchimp but if you’re like me and want to understand what is going on and how to build yours so you have full control then follow along as we send a few custom newsletters to our subscribers.
The Breakdown
Before we start writing any code let us breakdown what happens when you receive a new email and what might be happening. When you receive a newsletter from any platform you’re subscribed to, you notice that each one has a different design, logo, font. You can see the subject and a bold title and then we have the body and sometimes images. These are all contained in Templates
.
Most times, these are crafted with HTML, CSS and Javascript (pretty vanilla, I know). The HTML files can be either a .html
or .tmpl
A sample template would usually start with the usual <!DOCTYPE html>. Here’s a sample template:
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My Newsletter</title> <style> /* Add CSS styles here */ </style>
</head>
<body> <header> <h1>Welcome to My Newsletter</h1> </header> <main> <!-- Newsletter content goes here --> </main> <footer> <p>© 2024 My Company. All rights reserved.</p> </footer>
</body>
</html>
Dynamic templates
It would be a hassle, if we had to constantly edit the html file every time we wanted to send new content to our subscribers, luckily there’s a way we can maintain the base feel of our newsletter while dynamically changing what our users see whenever they receive an email from us.
Using Go Templates
In Go, the html/template package allows us to create dynamic HTML content using template files. These templates can include placeholders or variables that are replaced with actual data when rendering the template.
Let’s take a look at an example template file (newsletter_template.html):
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{.Title}}</title> <style> /* Add CSS styles here */ </style>
</head>
<body> <header> <h1>{{.Header}}</h1> </header> <main> <p>{{.Content}}</p> </main> <footer> <p>© {{.Year}} My Company. All rights reserved.</p> </footer>
</body>
</html>
In this template, we’ve defined placeholders like {{.Title}}
, {{.Header}}
, {{.Content}}
, and {{.Year}}
that will be dynamically replaced with actual data when rendering the template.
Rendering the Template in Go
Now, let’s see how we can render this template in a Go program:
package main import ( "html/template" "os"
) func main() { // Read template file tmpl, err := template.ParseFiles("newsletter_template.html") if err != nil { panic(err) } // Define data for template data := struct { Title string Header string Content string Year int }{ Title: "My Newsletter", Header: "Welcome to My Newsletter", Content: "This is a test newsletter. Enjoy!", Year: 2024, } // Execute template if err := tmpl.Execute(os.Stdout, data); err != nil { panic(err) }
}
In this Go program, we parse the template file (newsletter_template.html) and define the data to be used when rendering the template. We then execute the template, passing the data, and the rendered HTML is written to the standard output (os.Stdout).
Benefits of Dynamic Templates
Using dynamic templates offers several benefits:
Flexibility: With dynamic templates, we can easily update the content of our newsletters without modifying the underlying HTML structure. This allows for quick iteration and experimentation with different content layouts.
Personalisation: Dynamic templates enable us to personalise the content of each newsletter based on user preferences, demographics, or behaviour. We can tailor the message to resonate with each subscriber, increasing engagement and conversion rates.
Automation: By integrating dynamic templates with our newsletter delivery system, we can automate the process of sending personalised emails to subscribers. This saves time and effort while ensuring a consistent brand experience for recipients.
Preparing the Email Setup
Now that we have our email template with all the data we want to send, the next step is to actually send it out to our subscribers. In this section, we’ll explore how to accomplish this using Go and the gomail package.
Using the gomail Package
The Gomail is a package I developed that provides a simple and efficient way to send emails in Go. We’ll use it to compose our email message, including the HTML content from our template, and send it to our subscribers. We’ll need certain requirements in order to use the package:
-
Template Directory: To maintain organization and ease of management, it’s helpful to store all our email templates in a dedicated directory. This directory will hold the HTML templates we’ve created for our newsletters.
For example, we can create a directory named templates in our project directory and store all our template files there.
project_directory/
├── templates/
│ ├── newsletter_template.html
│ └── other_templates...
- Mail Credentials: We need credentials from an email client, you can get them from your favourite providers here’s how to get one for Google Gmail SMTP. Using Gomail we can add the credentials with the struct:
package main import ( "log" "github.com/rhaqim/gomail" ) func main() { auth := gomail.EmailAuthConfig{ Host: "smtp.gmail.com", Port: 587, Username: "user", Password: "password", From: "[email protected]", } templateDir := "templates" g := gomail.NewGoemail(auth, templatesDir) }
Note: I included the template directory and also created a new instance with the auth and templateDir
Sending the Email
Now that we have our email sender setup, we need to send the actual email. Gomail needs to know who you’re sending the email to, could be one or more people, include a subject, what template in the template directory you want to use and then the body of the message. Putting it all together we have the following:
package main import ( "log" "github.com/rhaqim/gomail" ) func main() { auth := gomail.EmailAuthConfig{ Host: "smtp.gmail.com", Port: 587, Username: "user", Password: "password", From: "[email protected]", } templateDir := "templates" g := gomail.NewGoemail(auth, templatesDir) NewsletterApp(g) } func NewsletterApp(mail gomail.Gomail) { email := &gomail.Email{ Recipients: []string{"[email protected]", "[email protected]"}, Subject: "Hello", Body: "Hello, this is a test email", TemplateFileName: "newsletter_template.html", } err := mail.SendEmail(email) if err != nil { log.Fatal(err) } }
Conclusion
This is an abstraction and the code for Gomail is publicly available. Feel free to fork and modify it for your own usecase. With the following you can design different templates and for different functions.