Zum Inhalt springen
Doku

Tutorial

E-Mails mit Go senden

Senden Sie E-Mails aus Go mit dem SDK emailit-go oder net/smtp, behandeln Sie API-Fehler und verifizieren Sie Emailit-Webhook-Signaturen in einem net/http-Handler.

Aktualisiert am 1. Okt. 2026

Diese Anleitung zeigt, wie Sie E-Mails aus einem Go-Dienst mit dem offiziellen SDK emailit-go senden, wie Sie stattdessen net/smtp verwenden und wie Sie Webhooks in einem net/http-Handler verifizieren.

Voraussetzungen

  • Go 1.21 oder neuer.
  • Eine verifizierte Versanddomain, zum Beispiel acme.com.
  • Ein API-Schlüssel. Ein reiner Sende-Schlüssel, der auf Ihre Domain beschränkt ist, genügt.
  • Solange Ihr Workspace keinen Produktionszugang hat, können Sie nur an die Konto-E-Mail-Adressen von Workspace-Mitgliedern senden.

SDK installieren

Terminal
go get github.com/emailit/emailit-go/v2

Das SDK hängt nur von der Go-Standardbibliothek ab.

API-Schlüssel konfigurieren

Übergeben Sie den Schlüssel als Umgebungsvariable an Ihren Prozess:

Terminal
export EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••

E-Mail senden

main.go
package main

import (
	"log"
	"os"

	"github.com/emailit/emailit-go/v2"
)

func main() {
	client := emailit.NewClient(os.Getenv("EMAILIT_API_KEY"))

	email, err := client.Emails.Send(&emailit.SendEmailRequest{
		From:    "Acme <hello@acme.com>",
		To:      []string{"ada@example.com"},
		Subject: "Your login code",
		Text:    "Your code is 482913. It expires in 10 minutes.",
		Html:    "<p>Your code is <strong>482913</strong>. It expires in 10 minutes.</p>",
	})
	if err != nil {
		log.Fatal(err)
	}

	log.Println("sent", email.Id) // em_…
}

Erstellen Sie den Client einmal und verwenden Sie ihn gemeinsam; er lässt sich gefahrlos über Anfragen hinweg wiederverwenden. Um eine gespeicherte Vorlage zu senden, setzen Sie Template auf ihren Alias oder ihre tem_-ID und übergeben Variables. Um Timeouts zu ändern, übergeben Sie Ihren eigenen Client: emailit.NewClient(key, emailit.WithHTTPClient(&http.Client{Timeout: 10 * time.Second})).

Fehler behandeln

Das SDK gibt gewöhnliche Go-Fehler zurück, mit Hilfsfunktionen, um sie einzuordnen:

Go
email, err := client.Emails.Send(req)
if err != nil {
	switch {
	case emailit.IsRateLimitError(err):
		// 429: back off and retry
	case emailit.IsAuthenticationError(err):
		// 401: the API key is missing or invalid
	case emailit.IsUnprocessableEntityError(err):
		// 422: for example, the from domain isn't verified
	}

	var apiErr *emailit.APIError
	if errors.As(err, &apiErr) {
		log.Printf("emailit: %d %s", apiErr.StatusCode, apiErr.Message)
	}
	return err
}

Alternativ per SMTP senden

net/smtp aus der Standardbibliothek kann über das Emailit-Relay senden. smtp.SendMail stuft die Verbindung per STARTTLS hoch, bevor es sich authentifiziert:

smtp.go
package main

import (
	"log"
	"net/smtp"
	"os"
	"strings"
)

func main() {
	auth := smtp.PlainAuth("", "emailit", os.Getenv("EMAILIT_API_KEY"), "smtp.emailit.com")

	msg := strings.Join([]string{
		"From: Acme <hello@acme.com>",
		"To: ada@example.com",
		"Subject: Your login code",
		"MIME-Version: 1.0",
		"Content-Type: text/plain; charset=UTF-8",
		"",
		"Your code is 482913. It expires in 10 minutes.",
	}, "\r\n")

	err := smtp.SendMail("smtp.emailit.com:587", auth, "hello@acme.com", []string{"ada@example.com"}, []byte(msg))
	if err != nil {
		log.Fatal(err)
	}
}

net/smtp ist minimal: Sie bauen die Nachricht selbst, und implizites TLS auf Port 465 gibt es nicht. Für HTML, Anhänge oder die Wiederverwendung von Verbindungen verwenden Sie eine gepflegte Mail-Bibliothek oder die API. Wenn Port 587 blockiert ist, verwenden Sie smtp.emailit.com:2525. Siehe SMTP-Einstellungen.

Webhooks empfangen

Erstellen Sie einen Webhook und speichern Sie sein Signatur-Secret in EMAILIT_WEBHOOK_SECRET. Der Handler liest den unveränderten Body, prüft die Signatur und dekodiert dann das Array der Events:

webhooks.go
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"io"
	"net/http"
	"os"
	"strconv"
	"time"
)

type emailitEvent struct {
	EventID string `json:"event_id"`
	Type    string `json:"type"`
	Data    struct {
		Object map[string]any `json:"object"`
	} `json:"data"`
}

func validSignature(body []byte, signature, timestamp, secret string) bool {
	ts, err := strconv.ParseInt(timestamp, 10, 64)
	if err != nil || signature == "" {
		return false
	}
	if age := time.Now().Unix() - ts; age > 300 || age < -300 {
		return false
	}
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(timestamp + "."))
	mac.Write(body)
	expected := hex.EncodeToString(mac.Sum(nil))
	return hmac.Equal([]byte(expected), []byte(signature))
}

func emailitWebhook(w http.ResponseWriter, r *http.Request) {
	body, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 10<<20))
	if err != nil {
		http.Error(w, "bad request", http.StatusBadRequest)
		return
	}

	if !validSignature(body, r.Header.Get("X-Emailit-Signature"), r.Header.Get("X-Emailit-Timestamp"), os.Getenv("EMAILIT_WEBHOOK_SECRET")) {
		http.Error(w, "invalid signature", http.StatusUnauthorized)
		return
	}

	var events []emailitEvent // up to 100 events per request
	if err := json.Unmarshal(body, &events); err != nil {
		http.Error(w, "bad request", http.StatusBadRequest)
		return
	}

	for _, event := range events {
		if event.Type == "email.bounced" {
			// Stop emailing event.Data.Object["to"].
		}
	}

	w.WriteHeader(http.StatusOK)
}

func main() {
	http.HandleFunc("POST /webhooks/emailit", emailitWebhook)
	http.ListenAndServe(":8080", nil)
}

Das Muster POST /path erfordert Go 1.22 oder neuer; unter Go 1.21 registrieren Sie /webhooks/emailit und prüfen r.Method selbst. Geben Sie innerhalb von 30 Sekunden einen 2xx-Status zurück; bei anderen Antworten wird die Anfrage wiederholt. Siehe Anfragesignatur.

Tipps für den Produktivbetrieb

  • Unter dem Rate Limit bleiben. Neue Workspaces können standardmäßig 2 E-Mails pro Sekunde und 5.000 pro Tag senden. Senden Sie Massen-E-Mails aus einem Worker mit einem Rate Limiter wie golang.org/x/time/rate. Siehe Limits.
  • Wiederholungen sicher machen. Wenn Sie nach einem Timeout erneut senden, übergeben Sie mit net/http einen Header Idempotency-Key, damit die E-Mail nicht doppelt gesendet wird. Siehe Idempotenz.
  • Webhooks deduplizieren, indem Sie jede verarbeitete EventID speichern.
  • Timeouts setzen. Verwenden Sie einen Context oder ein Timeout für den HTTP-Client, damit ein langsames Netzwerk keine Request-Goroutinen blockiert.

Nächste Schritte

Anhänge, Planung und Tracking.
Header und wie Sie mit Backoff reagieren.
Alle Events und ihre Payloads.
Alle offiziellen Bibliotheken.

War diese Seite hilfreich?

Danke für Ihr Feedback.

Danke, wir lesen jede Nachricht.