Design Newsletter Emails in Golang

rhaqim

Rhaqim

Posted on April 17, 2024

Design Newsletter Emails in Golang

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>&copy; 2024 My Company. All rights reserved.</p>
    </footer>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

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>&copy; {{.Year}} My Company. All rights reserved.</p>
    </footer>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

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...
Enter fullscreen mode Exit fullscreen mode
  • 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:     "me@gmail.com",
        }

        templateDir := "templates"

        g := gomail.NewGoemail(auth, templatesDir)
    }
Enter fullscreen mode Exit fullscreen mode

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:     "me@gmail.com",
        }

        templateDir := "templates"

        g := gomail.NewGoemail(auth, templatesDir)

        NewsletterApp(g)

    }

    func NewsletterApp(mail gomail.Gomail) {

        email := &gomail.Email{
            Recipients:       []string{"recipient1e@gmail.com", "recipiente2@gmail.com"},
            Subject:          "Hello",
            Body:             "Hello, this is a test email",
            TemplateFileName: "newsletter_template.html",
        }

        err := mail.SendEmail(email)
        if err != nil {
            log.Fatal(err)
        }
    }
Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
rhaqim
Rhaqim

Posted on April 17, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related