# 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.

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](/de/docs/domains/add-a-domain/), zum Beispiel `acme.com`.
- Ein [API-Schlüssel](/de/docs/developers/api-keys/). Ein reiner Sende-Schlüssel, der auf Ihre Domain beschränkt ist, genügt.
- Solange Ihr Workspace keinen [Produktionszugang](/de/docs/workspaces/production-access/) hat, können Sie nur an die Konto-E-Mail-Adressen von Workspace-Mitgliedern senden.

## SDK installieren

```bash
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:

```bash
```

## E-Mail senden

```go title="main.go"
package main

	"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:

```go title="smtp.go"
package main

	"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](/de/docs/smtp/settings/).

## Webhooks empfangen

[Erstellen Sie einen Webhook](/de/docs/webhooks/set-up/) 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:

```go title="webhooks.go"
package main

	"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](/de/docs/webhooks/request-signature/).

## 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](/de/docs/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](/de/docs/email-api/idempotency/).
- **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

  - [E-Mails per API senden](/de/docs/email-api/send-email/): Anhänge, Planung und Tracking.
  - [Rate Limits](/de/docs/api-reference/rate-limits/): Header und wie Sie mit Backoff reagieren.
  - [Webhook-Event-Typen](/de/docs/webhooks/event-types/): Alle Events und ihre Payloads.
  - [SDKs und Bibliotheken](/de/docs/sdks/): Alle offiziellen Bibliotheken.

---
Quelle: https://emailit.com/de/docs/frameworks/go/
