Skip to content
Beranda Blog Mengirim Email Menggunakan Go dan Gmail
Development 5 menit baca

Mengirim Email Menggunakan Go dan Gmail

Nurul

Nurul

Lead & Fullstack Engineer · 5 April 2024

Panduan langkah demi langkah mengintegrasikan Gmail SMTP dengan Go — pengaturan app password, paket mailer yang bisa dipakai ulang dengan template HTML, dan contoh pengiriman yang berfungsi.

Kalau Anda perlu mengirim email dari aplikasi Go, server SMTP milik Gmail adalah salah satu opsi paling sederhana untuk dijalankan. Tidak perlu akun layanan email pihak ketiga — cukup akun Google dan app password yang dibuat sendiri.

Menyiapkan App Password Gmail

Google mensyaratkan app password, bukan password akun biasa Anda, saat login lewat SMTP. Untuk membuatnya:

  1. Buka Akun Google → Keamanan → App password (Verifikasi 2 Langkah harus aktif).
  2. Buat app password baru untuk "Mail".
  3. Salin password yang dihasilkan — Anda akan memakainya di konfigurasi di bawah. Hapus spasi apa pun sebelum menyimpannya.

Struktur Proyek

Kita letakkan semuanya dalam paket mailer di dalam folder mail/:

mail/
  setup.go        — konfigurasi SMTP, inisialisasi singleton
  usecase.go      — struct Mailer, pembangun body, method Send
  sample.template — template email HTML

Pengaturan SMTP (mail/setup.go)

Pengaturannya diinisialisasi sekali memakai sync.Once, sehingga objek auth SMTP hanya dibuat satu kali berapa pun banyak email yang Anda kirim:

package mailer

import (
    "fmt"
    "net/smtp"
    "sync"
)

type SMTPMailSetup struct {
    Server   string
    Port     string
    Address  string
    Sender   string
    Password string
    Auth     smtp.Auth
}

var mailSetup *SMTPMailSetup
var once sync.Once

func getSetup() *SMTPMailSetup {
    once.Do(func() {
        mailSetup = &SMTPMailSetup{
            Server:   "smtp.gmail.com",
            Port:     "587",
            Sender:   "your_email@gmail.com",
            Password: "your_app_password",
        }
        mailSetup.Address = fmt.Sprintf("%s:%s", mailSetup.Server, mailSetup.Port)
        mailSetup.Auth = smtp.PlainAuth("", mailSetup.Sender, mailSetup.Password, mailSetup.Server)
    })
    return mailSetup
}

Di proyek sungguhan, ambil Sender dan Password dari environment variable — jangan pernah menuliskan kredensial langsung di file sumber.

Usecase Mailer (mail/usecase.go)

Struct Mailer menyediakan satu method Send. Di dalamnya ia membangun body HTML dari file template Go sebelum menyerahkannya ke smtp.SendMail:

package mailer

import (
    "bytes"
    "fmt"
    "net/smtp"
    "text/template"
)

type Mailer struct {
    Body  []byte
    Setup *SMTPMailSetup
}

func NewSMTPMailer() *Mailer {
    return &Mailer{Setup: getSetup()}
}

func (m *Mailer) createBody(subject, htmlTemplate string, data any) (err error) {
    var body bytes.Buffer
    const mime = "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
    body.Write([]byte(fmt.Sprintf("Subject: %s\n%s\n\n", subject, mime)))

    t, err := template.ParseFiles(htmlTemplate)
    if err != nil {
        return
    }
    err = t.Execute(&body, data)
    if err != nil {
        return
    }
    m.Body = body.Bytes()
    return nil
}

func (m *Mailer) Send(recipient, subject, tmpl string, data any) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("error on sending email: %v", r)
        }
    }()
    err = m.createBody(subject, tmpl, data)
    if err != nil {
        return
    }
    err = smtp.SendMail(m.Setup.Address, m.Setup.Auth, m.Setup.Sender, []string{recipient}, m.Body)
    return
}

Parameter data any diteruskan ke template Go, jadi Anda bisa menyuntikkan nilai dinamis — nama pengguna, tautan verifikasi, ringkasan pesanan — dengan mendefinisikan field di sebuah struct lalu merujuknya memakai {{ .FieldName }} di template.

Template HTML (mail/sample.template)

<!DOCTYPE html>
<html>
<body>
    Sending email from a Go app!
</body>
</html>

Ganti bagian ini dengan HTML email Anda yang sebenarnya. Anda bisa merujuk field mana pun dari struct data memakai sintaks template Go standar.

Menyatukan Semuanya (main.go)

package main

import (
    "log"
    "time"
    mailer "yourmodule/mail"
)

func main() {
    mail := mailer.NewSMTPMailer()

    err := mail.Send(
        "recipient@example.com",
        "Test Email",
        "./mail/sample.template",
        nil,
    )
    if err != nil {
        log.Println(err)
    }

    time.Sleep(30 * time.Second)
}

Catatan untuk Penggunaan Produksi

  • Pakai environment variable untuk Sender dan Password — jangan pernah menaruh kredensial di version control.
  • Cache templatetemplate.ParseFiles membaca dari disk setiap kali dipanggil. Untuk pengiriman bervolume tinggi, parse template sekali saat startup dan simpan di struct Mailer.
  • Batas harian Gmail — akun Gmail gratis dibatasi sekitar 500 email per hari lewat SMTP. Untuk email transaksional dalam skala besar, pertimbangkan layanan khusus seperti SendGrid atau Amazon SES.
  • TLSsmtp.SendMail pada port 587 memakai STARTTLS secara otomatis, jadi koneksinya terenkripsi saat transit.

Kode sumber lengkapnya tersedia di github.com/uhkrowi/go-gmail-mailer.

Penulis

Nurul

Nurul

Lead & Fullstack Engineer

Bagian dari tim SimpleFunc yang membangun solusi bersih dan skalabel untuk bisnis di seluruh Indonesia.

Kerja Sama

Punya proyek? Mari kita diskusikan bagaimana kami bisa membantu membangunnya.

Hubungi Kami