knadh/listmonk · warning
unsupported bounce type: %v
Error message
unsupported bounce type: %v
What it means
Postmark bounce notifications carry a Type field classifying the bounce. ProcessBounce only maps a fixed set of Postmark bounce types (HardBounce, BadEmailAddress, ManuallyDeactivated, SoftBounce, Transient, DnsError, SpamNotification, VirusNotification, DMARCPolicy, SpamComplaint); anything else returns 'unsupported bounce type'. This prevents unmapped Postmark events from being recorded with a wrong bounce class.
Source
Thrown at internal/bounce/webhooks/postmark.go:83
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 = false
}
if !supportedBounceType {
return nil, fmt.Errorf("unsupported bounce type: %v", n.Type)
}
// Look for the campaign ID in headers.
campUUID := ""
if v, ok := n.Metadata["X-Listmonk-Campaign"]; ok {
campUUID = v
}
return []models.Bounce{{
Email: strings.ToLower(n.Email),
CampaignUUID: campUUID,
Type: typ,
Source: "postmark",
Meta: json.RawMessage(b),
CreatedAt: n.BouncedAt,
}}, nil
}
View on GitHub (pinned to 670c01717d)
Solutions
- Check the logged n.Type value and compare against the supported list in internal/bounce/webhooks/postmark.go
- Restrict the Postmark webhook to the bounce/spam events listmonk supports
- Update the switch statement to map the new Postmark Type to hard/soft/complaint and rebuild
- If the type is informational only, filter it out at the Postmark webhook configuration level
Example fix
// before (postmark.go)
case "SpamComplaint":
typ = models.BounceTypeComplaint
default:
supportedBounceType = false
// after
case "SpamComplaint":
typ = models.BounceTypeComplaint
case "NewPostmarkType":
typ = models.BounceTypeSoft
default:
supportedBounceType = false Defensive patterns
Strategy: type-guard
Validate before calling
var supportedPostmarkTypes = map[string]bool{
"HardBounce": true, "BadEmailAddress": true, "ManuallyDeactivated": true,
"SoftBounce": true, "Transient": true, "DnsError": true,
"SpamNotification": true, "VirusNotification": true,
"DMARCPolicy": true, "SpamComplaint": true,
}
func isSupportedPostmarkType(t string) bool { return supportedPostmarkTypes[t] }
// inspect n.Type before/after calling ProcessBounce and skip unsupported events Type guard
func isPostmarkBounceRecord(n json.RawMessage) (isBounce, supported bool) {
var probe struct {
RecordType string `json:"RecordType"`
Type string `json:"Type"`
}
if json.Unmarshal(n, &probe) != nil { return false, false }
return probe.RecordType == "Bounce" || probe.RecordType == "SpamComplaint",
supportedPostmarkTypes[probe.Type]
} Try / catch
bounces, err := handler.ProcessBounce(body, c)
if err != nil {
var unsupported string
if _, e := fmt.Sscanf(err.Error(), "unsupported bounce type: %s", &unsupported); e == nil {
c.Logger().Warnf("ignoring unsupported postmark type: %s", unsupported)
return c.NoContent(http.StatusOK) // acknowledge so Postmark stops retrying
}
return err
} Prevention
- Track Postmark docs for new bounce Types and update the switch when they appear
- Configure the Postmark webhook to send only supported events
- Return 200 for ignorable events so Postmark does not retry indefinitely
When it happens
Trigger: A Postmark webhook fires with RecordType 'Bounce' or 'SpamComplaint' but a Type value outside the supported switch list, e.g. 'AntiSpam'/'Unknown' types, new Postmark bounce types introduced after this code was written, or a SpamComplaint RecordType carrying an unexpected Type value.
Common situations: Postmark adds a new bounce Type (product update) not yet handled; enabling Postmark message streams that emit types listmonk doesn't map; test events from Postmark's webhook tester with exotic types; misconfigured webhook subscribed to all events instead of bounce events.
Related errors
- error unmarshalling postmark notification: %v
- invalid timestamp in signature: %v
- invalid signature format
- error unmarshalling Sendgrid notification: %v
- error asn1 unmarshal of signature: %v
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/b882328fb734144e.
Report an issue: GitHub.