Integration

Send emails from Go (net/http) with Postkit

Send transactional emails from Go services using net/http. Zero dependencies, idiomatic Go.

1. Set your API key

# shell
export POSTKIT_API_KEY=pk_live_...

2. Send an email

go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

func sendWelcome(w http.ResponseWriter, r *http.Request) {
	payload, _ := json.Marshal(map[string]string{
		"from":    "hello@yourapp.eu",
		"to":      "user@example.com",
		"subject": "Welcome aboard!",
		"html":    "<h1>Welcome!</h1>",
	})

	req, _ := http.NewRequest("POST",
		"https://api.postkit.eu/v1/emails",
		bytes.NewReader(payload),
	)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("POSTKIT_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer resp.Body.Close()

	w.Header().Set("Content-Type", "application/json")
	io.Copy(w, resp.Body)
}

func main() {
	http.HandleFunc("/send", sendWelcome)
	fmt.Println("Listening on :8080")
	http.ListenAndServe(":8080", nil)
}

3. Handle webhooks

Postkit sends delivery events (sent, delivered, bounced, opened, clicked) via HMAC-SHA256 signed webhooks following the Standard Webhooks specification.

go
func postkitWebhook(w http.ResponseWriter, r *http.Request) {
	body, _ := io.ReadAll(r.Body)
	msgID := r.Header.Get("webhook-id")
	timestamp := r.Header.Get("webhook-timestamp")
	signature := r.Header.Get("webhook-signature")

	secretB64 := strings.TrimPrefix(os.Getenv("POSTKIT_WEBHOOK_SECRET"), "whsec_")
	secret, _ := base64.StdEncoding.DecodeString(secretB64)
	content := fmt.Sprintf("%s.%s.%s", msgID, timestamp, string(body))

	mac := hmac.New(sha256.New, secret)
	mac.Write([]byte(content))
	expected := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	valid := false
	for _, sig := range strings.Split(signature, " ") {
		val := strings.TrimPrefix(sig, "v1,")
		if hmac.Equal([]byte(val), []byte(expected)) {
			valid = true
			break
		}
	}

	if !valid {
		http.Error(w, "Invalid signature", http.StatusUnauthorized)
		return
	}

	log.Printf("Postkit event received")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"received":true}`))
}

Start sending in under 5 minutes

Free plan. No credit card required.

Get Started Free