Aller au contenu
Docs

Tutoriel

Envoyez des e-mails depuis Go avec le SDK emailit-go ou net/smtp, gérez les erreurs de l’API et vérifiez les signatures des webhooks Emailit dans un handler net/http.

Mis à jour le 1 oct. 2026

Ce guide montre comment envoyer des e-mails depuis un service Go avec le SDK officiel emailit-go, comment utiliser plutôt net/smtp, et comment vérifier les webhooks dans un handler net/http.

Prérequis

  • Go 1.21 ou version ultérieure.
  • Un domaine d’envoi vérifié, par exemple acme.com.
  • Une clé API. Une clé Sending Only limitée à votre domaine suffit.
  • Tant que votre espace de travail n’a pas l’accès production, vous ne pouvez envoyer qu’aux adresses e-mail des comptes des membres de l’espace de travail.

Installer le SDK

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

Le SDK ne dépend que de la bibliothèque standard de Go.

Configurer votre clé API

Transmettez la clé à votre processus dans une variable d’environnement :

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

Envoyer un e-mail

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_…
}

Créez le client une seule fois et partagez-le : il peut être réutilisé sans risque d’une requête à l’autre. Pour envoyer un modèle enregistré, définissez Template sur son alias ou son ID tem_ et transmettez Variables. Pour modifier les timeouts, transmettez votre propre client : emailit.NewClient(key, emailit.WithHTTPClient(&http.Client{Timeout: 10 * time.Second})).

Gérer les erreurs

Le SDK renvoie des erreurs Go ordinaires, avec des fonctions utilitaires pour les classer :

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
}

Envoyer plutôt via SMTP

Le paquet net/smtp de la bibliothèque standard peut envoyer via le relais Emailit. smtp.SendMail passe la connexion en STARTTLS avant de s’authentifier :

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 est minimal : vous construisez le message vous-même, et il ne gère pas le TLS implicite sur le port 465. Pour le HTML, les pièces jointes ou la réutilisation des connexions, utilisez une bibliothèque d’e-mail maintenue ou l’API. Si le port 587 est bloqué, utilisez smtp.emailit.com:2525. Consultez Paramètres SMTP.

Recevoir des webhooks

Créez un webhook et enregistrez son secret de signature dans EMAILIT_WEBHOOK_SECRET. Le handler lit le corps brut, vérifie la signature, puis décode le tableau d’événements :

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)
}

Le motif POST /path nécessite Go 1.22 ou une version ultérieure ; avec Go 1.21, enregistrez /webhooks/emailit et vérifiez r.Method vous-même. Renvoyez un 2xx dans les 30 secondes ; pour toute autre réponse, Emailit réessaie. Consultez Signature des requêtes.

Conseils pour la production

  • Restez sous votre limite de débit. Par défaut, les nouveaux espaces de travail peuvent envoyer 2 e-mails par seconde et 5 000 par jour. Envoyez les e-mails en masse depuis un worker doté d’un limiteur de débit comme golang.org/x/time/rate. Consultez Limites.
  • Sécurisez les relances. Si vous relancez une requête après un timeout, envoyez un en-tête Idempotency-Key avec net/http pour que l’e-mail ne soit pas envoyé deux fois. Consultez Idempotence.
  • Dédoublonnez les webhooks en enregistrant chaque EventID traité.
  • Définissez des timeouts. Utilisez un contexte ou un timeout de client HTTP pour qu’un réseau lent ne bloque pas les goroutines de requête.

Étapes suivantes

Pièces jointes, programmation et suivi.
Les en-têtes et comment ralentir vos envois.
Tous les événements et leur payload.
Toutes les bibliothèques officielles.

Cette page vous a-t-elle été utile ?

Merci pour votre retour.

Merci, nous lisons chaque message.