AhaSend
Terug naar Blog

De complete gids voor het versturen van transactionele e-mails in Go

Mark Kraakman
Mark Kraakman
Guides

Go-ontwikkelaars hebben twee goede opties voor het versturen van transactionele e-mail met AhaSend: de HTTP API via de officiële Go SDK (aanbevolen voor de meeste toepassingen) en SMTP relay (handig als je al werkt met bestaande Go e-mailbibliotheken). Deze gids behandelt beide opties, van installatie tot een productierijp voorbeeld met foutafhandeling en webhook-verwerking.

Vereisten

Heb je je domein nog niet ingesteld? Volg dan eerst de domeinconfiguratiegids. Je kunt niet versturen vanuit een niet-geverifieerd domein.

Optie 1: HTTP API met de AhaSend Go SDK

De Go SDK is de aanbevolen aanpak. Je krijgt volledige API-dekking, ingebouwde rate limiting, automatische retries met exponential backoff, idempotentiebescherming en webhook-verificatie direct beschikbaar.

SDK installeren

go get github.com/AhaSend/ahasend-go

De SDK heeft minimale afhankelijkheden - alleen github.com/google/uuid en github.com/stretchr/testify (voor tests).

Credentials instellen

Bewaar credentials als omgevingsvariabelen, nooit in je broncode:

export AHASEND_API_KEY="aha-sk-your-64-character-key"
export AHASEND_ACCOUNT_ID="your-account-id-here"

Je vindt beide waarden in je AhaSend-dashboard.

Je eerste e-mail versturen

package main

import (
    "context"
    "log"
    "os"

    "github.com/AhaSend/ahasend-go"
    "github.com/google/uuid"
)

func main() {
    apiKey := os.Getenv("AHASEND_API_KEY")
    accountID := uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID"))

    client := ahasend.NewAPIClient(ahasend.NewConfiguration())
    ctx := context.WithValue(context.Background(),
        ahasend.ContextAccessToken, apiKey)

    message := ahasend.CreateMessageRequest{
        From: ahasend.SenderAddress{Email: "[email protected]"},
        Recipients: []ahasend.Recipient{
            {Email: "[email protected]"},
        },
        Subject:     "Welkom bij je app",
        HtmlContent: ahasend.PtrString("<h1>Welkom!</h1><p>Bedankt voor je aanmelding.</p>"),
        TextContent: ahasend.PtrString("Welkom! Bedankt voor je aanmelding."),
    }

    response, _, err := client.MessagesAPI.CreateMessage(ctx, accountID, message)
    if err != nil {
        log.Fatalf("E-mail versturen mislukt: %v", err)
    }

    log.Printf("E-mail verstuurd. Bericht-ID: %s", *response.Data[0].Id)
}

API-sleutel op clientniveau instellen

Voor applicaties die veel e-mails versturen, stel je de API-sleutel eenmalig in op de client in plaats van deze bij elk verzoek via de context mee te geven:

client := ahasend.NewAPIClient(
    ahasend.WithAPIKey(os.Getenv("AHASEND_API_KEY")),
)

// Alle volgende aanroepen gebruiken deze sleutel automatisch
response, _, err := client.MessagesAPI.CreateMessage(ctx, accountID, message)

Een praktijkvoorbeeld: bevestigingsmail bij registratie

In de praktijk verstuur je e-mail als onderdeel van een applicatieflow. Hieronder zie je een welkomstmail vanuit een Go HTTP-handler, met correcte foutafhandeling:

package handlers

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"

    "github.com/AhaSend/ahasend-go"
    "github.com/google/uuid"
)

var (
    emailClient *ahasend.APIClient
    accountID   uuid.UUID
)

func init() {
    emailClient = ahasend.NewAPIClient(
        ahasend.WithAPIKey(os.Getenv("AHASEND_API_KEY")),
    )
    accountID = uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID"))
}

func sendWelcomeEmail(ctx context.Context, userEmail, userName string) error {
    htmlBody := fmt.Sprintf(`
        <h1>Welkom, %s!</h1>
        <p>Je account is klaar. Je kunt op elk moment inloggen.</p>
        <p>Vragen? Beantwoord gewoon deze e-mail.</p>
    `, userName)

    textBody := fmt.Sprintf(
        "Welkom, %s! Je account is klaar. Vragen? Beantwoord gewoon deze e-mail.",
        userName,
    )

    message := ahasend.CreateMessageRequest{
        From: ahasend.SenderAddress{
            Email: "[email protected]",
            Name:  ahasend.PtrString("Jouw App"),
        },
        Recipients: []ahasend.Recipient{
            {
                Email: userEmail,
                Name:  ahasend.PtrString(userName),
            },
        },
        Subject:     "Welkom bij Jouw App",
        HtmlContent: ahasend.PtrString(htmlBody),
        TextContent: ahasend.PtrString(textBody),
    }

    _, _, err := emailClient.MessagesAPI.CreateMessage(ctx, accountID, message)
    return err
}

func RegisterHandler(w http.ResponseWriter, r *http.Request) {
    // ... je registratielogica ...

    if err := sendWelcomeEmail(r.Context(), newUser.Email, newUser.Name); err != nil {
        // Loggen maar de registratie niet afbreken. Een tijdelijk e-mailprobleem
        // mag de aanmaak van een account niet blokkeren. Volg de aflevering via webhooks.
        log.Printf("Waarschuwing: welkomstmail versturen naar %s mislukt: %v", newUser.Email, err)
    }

    w.WriteHeader(http.StatusCreated)
}

Aflevergebeurtenissen verwerken met webhooks

De SDK bevat Standard Webhooks-conforme verwerking met HMAC-SHA256-handtekeningverificatie. Stel een webhook-endpoint in via je AhaSend-dashboard, sla het geheim op als omgevingsvariabele en verwerk de events in je applicatie:

package main

import (
    "log"
    "net/http"
    "os"

    "github.com/AhaSend/ahasend-go/webhooks"
)

func main() {
    verifier, err := webhooks.NewWebhookVerifier(os.Getenv("AHASEND_WEBHOOK_SECRET"))
    if err != nil {
        log.Fatalf("Verifier aanmaken mislukt: %v", err)
    }

    http.HandleFunc("/webhooks/ahasend", func(w http.ResponseWriter, r *http.Request) {
        event, err := verifier.ParseRequest(r)
        if err != nil {
            http.Error(w, "Ongeldige webhook", http.StatusBadRequest)
            return
        }

        switch e := event.(type) {
        case *webhooks.MessageDeliveredEvent:
            log.Printf("Afgeleverd bij %s", e.Data.Recipient)
        case *webhooks.MessageBouncedEvent:
            // Markeer dit adres als onbestelbaar in je database
            log.Printf("Bounce: %s - reden: %s", e.Data.Recipient, e.Data.Reason)
        case *webhooks.MessageOpenedEvent:
            log.Printf("Geopend door %s", e.Data.Recipient)
        case *webhooks.MessageClickedEvent:
            log.Printf("Link aangeklikt door %s", e.Data.Recipient)
        }

        w.WriteHeader(http.StatusOK)
    })

    log.Println("Webhook-server luistert op :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Ondersteunde event-types: message.delivered, message.bounced, message.opened, message.clicked, plus suppression.*, domain.* en route.* events.

Zie webhook_processing.go in de SDK-repository voor een volledig werkend webhook-servervoorbeeld.

Rate limiting en retry-configuratie

De SDK beheert rate limiting automatisch. Voor grootschalig gebruik kun je het verder afstemmen:

// Configureren voor grote verzendvolumes
client.SetSendMessageRateLimit(500, 1000) // 500 verzoeken/s, burst van 1000

// Retry-gedrag configureren
config := &ahasend.RetryConfig{
    Enabled:         true,
    MaxRetries:      3,
    BackoffStrategy: ahasend.ExponentialBackoff,
    BaseDelay:       time.Second,
    MaxDelay:        30 * time.Second,
}
client.SetRetryConfig(config)

Optie 2: SMTP met gomail

Migreer je van een andere provider en wil je zo min mogelijk code aanpassen? Of heeft je framework al ingebouwde SMTP-ondersteuning? Gebruik dan gomail met de SMTP-relay van AhaSend.

gomail installeren

go get gopkg.in/gomail.v2

SMTP-instellingen

Host:     send.ahasend.com
Poorten:  25, 587, 2525 (alle ondersteunen STARTTLS)
Auth:     Verplicht

SMTP-credentials zijn apart van je API-sleutel. Maak ze aan in je dashboard onder Credentials.

Versturen via SMTP

package main

import (
    "fmt"
    "log"
    "os"

    gomail "gopkg.in/gomail.v2"
)

func main() {
    m := gomail.NewMessage()
    m.SetAddressHeader("From", "[email protected]", "Jouw App")
    m.SetAddressHeader("To", "[email protected]", "Naam Ontvanger")
    m.SetHeader("Subject", "Hallo via AhaSend")
    m.SetBody("text/plain", "Deze e-mail is verstuurd via de SMTP-relay van AhaSend.")
    m.AddAlternative("text/html", "<p>Deze e-mail is verstuurd via de SMTP-relay van AhaSend.</p>")

    d := gomail.NewDialer(
        "send.ahasend.com",
        587,
        os.Getenv("AHASEND_SMTP_USER"),
        os.Getenv("AHASEND_SMTP_PASSWORD"),
    )

    if err := d.DialAndSend(m); err != nil {
        log.Fatalf("Versturen mislukt: %v", err)
    }

    fmt.Println("E-mail verstuurd.")
}

Welke methode moet je kiezen?

Gebruik de Go SDK als je een nieuwe applicatie bouwt of volledige zichtbaarheid wil over de afleveringsstatus, bounce-afhandeling, webhook-events en statistieken. De SDK regelt retries, rate limiting en idempotentie voor je.

Gebruik SMTP als je migreert van een andere provider en zo weinig mogelijk code wil aanpassen.

Productierijpe voorbeelden

De SDK-repository bevat 11 complete, uitvoerbare voorbeelden:

Een voorbeeld uitvoeren:

export AHASEND_API_KEY="jouw-api-sleutel"
export AHASEND_ACCOUNT_ID="jouw-account-id"

go run examples/send_email.go

Let op: alle voorbeeldbestanden gebruiken //go:build ignore, zodat ze afzonderlijk uitvoerbaar zijn zonder conflicten met go build ./....

Vervolgstappen

Vragen? Stuur een e-mail naar [email protected] of kom langs in onze Discord.

De complete gids voor het versturen van transactionele e-mails in Go | AhaSend