knadh/listmonk · error
error unmarshalling postmark notification: %v
Error message
error unmarshalling postmark notification: %v
What it means
Postmark's ProcessBounce first verifies basic-auth, then JSON-unmarshals the raw request body into postmarkNotif. If the body is not valid JSON or its fields don't match expected types (e.g. a string where an int is expected), the webhook returns 'error unmarshalling postmark notification'.
Source
Thrown at internal/bounce/webhooks/postmark.go:61
func NewPostmark(username, password string) *Postmark {
return &Postmark{
authHandler: middleware.BasicAuth(makePostmarkAuthHandler(username, password))(func(c echo.Context) error {
return nil
}),
}
}
// ProcessBounce processes Postmark bounce notifications and returns one object.
func (p *Postmark) ProcessBounce(b []byte, c echo.Context) ([]models.Bounce, error) {
// Do basicauth.
if err := p.authHandler(c); err != nil {
return nil, err
}
var n postmarkNotif
if err := json.Unmarshal(b, &n); err != nil {
return nil, fmt.Errorf("error unmarshalling postmark notification: %v", err)
}
// Ignore irrelevant messages.
if n.RecordType != "Bounce" && n.RecordType != "SpamComplaint" {
return nil, nil
}
supportedBounceType := true
typ := models.BounceTypeHard
switch n.Type {
case "HardBounce", "BadEmailAddress", "ManuallyDeactivated":
typ = models.BounceTypeHard
case "SoftBounce", "Transient", "DnsError", "SpamNotification", "VirusNotification", "DMARCPolicy":
typ = models.BounceTypeSoft
case "SpamComplaint":
typ = models.BounceTypeComplaint
default:
supportedBounceType = falseView on GitHub (pinned to 670c01717d)
Solutions
- Log the raw request body when this error occurs and validate it with a JSON linter
- Verify Postmark webhook is configured to POST application/json to the correct listmonk bounce URL
- Send a representative Postmark Bounce payload (with RecordType, ID as number, Metadata as string map) when testing
- Check for proxies/load balancers returning HTML error bodies to the endpoint
Example fix
// before
curl -X POST .../bounce -d 'RecordType=Bounce'
// after
curl -X POST .../bounce -H 'Content-Type: application/json' -d '{"RecordType":"Bounce","ID":1,"Type":"HardBounce","Email":"a@b.c","BouncedAt":"2024-01-01T00:00:00Z","Metadata":{}}' Defensive patterns
Strategy: validation
Validate before calling
func validPostmarkBody(b []byte) bool {
var probe struct {
RecordType string `json:"RecordType"`
ID int `json:"ID"`
Type string `json:"Type"`
Email string `json:"Email"`
Metadata map[string]string `json:"Metadata"`
}
return json.Unmarshal(b, &probe) == nil && probe.RecordType != ""
}
// return 400 with a clear message if !validPostmarkBody(body) Try / catch
bounces, err := handler.ProcessBounce(body, c)
if err != nil {
if strings.HasPrefix(err.Error(), "error unmarshalling postmark notification") {
c.Logger().Errorf("postmark body: %s", string(body))
return echo.NewHTTPError(http.StatusBadRequest, "invalid JSON payload")
}
return err
} Prevention
- Always send application/json to the bounce endpoint
- Use Postmark's official sample bounce payloads when testing
- Capture and log raw bodies on 4xx to spot proxy-injected HTML pages
- Pin Postmark webhook to Bounce and SpamComplaint events only
When it happens
Trigger: The Postmark webhook endpoint receives a body that fails json.Unmarshal: empty body, HTML error page from a misrouted request, form-encoded data, malformed JSON, or a JSON body with wrong types for fields like ID (int) or Metadata (map[string]string).
Common situations: Testing the endpoint with cURL and sending plain text or missing Content-Type; a proxy returning an HTML 502 page as the body; Postmark schema changes adding unexpected types; pointing Postmark at the wrong URL so another route's response is posted; sending test payloads with Metadata values that aren't strings.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- error unmarshalling Sendgrid notification: %v
- error unmarshalling SNS notification: %v
- error unmarshalling SES notification: %v
- unsupported bounce type: %v
- error parsing lang file: %s: %v
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/3cd82cab8aeedcc1.
Report an issue: GitHub.