checkSuppression rejects a send when any recipient (To/CC/BCC) is on the tenant's suppression list (decision 9). Returns a structured recipient_suppressed 422. Fails OPEN on a store error — a suppression-DB hiccup must not block legitimate mail; the list is protective, not a hard gate, and the stora
(ctx context.Context, userID string, req outbound.SendRequest)
| 1094 | // hiccup must not block legitimate mail; the list is protective, not a hard |
| 1095 | // gate, and the storage trigger / SES account-level list backstop it. |
| 1096 | func (a *API) checkSuppression(ctx context.Context, userID string, req outbound.SendRequest) *OutboundError { |
| 1097 | addrs := make([]string, 0, len(req.To)+len(req.CC)+len(req.BCC)) |
| 1098 | addrs = append(addrs, req.To...) |
| 1099 | addrs = append(addrs, req.CC...) |
| 1100 | addrs = append(addrs, req.BCC...) |
| 1101 | if len(addrs) == 0 { |
| 1102 | return nil |
| 1103 | } |
| 1104 | suppressed, err := a.store.SuppressedAddresses(ctx, userID, addrs) |
| 1105 | if err != nil { |
| 1106 | log.Printf("[api] suppression check failed (allowing send): %v", err) |
| 1107 | return nil |
| 1108 | } |
| 1109 | if len(suppressed) > 0 { |
| 1110 | return &OutboundError{http.StatusUnprocessableEntity, "recipient_suppressed", |
| 1111 | "recipient(s) on the suppression list: " + strings.Join(suppressed, ", ") + |
| 1112 | " — remove via DELETE /v1/account/suppressions/{address}"} |
| 1113 | } |
| 1114 | return nil |
| 1115 | } |
| 1116 | |
| 1117 | // DeliverOutbound is the shared send/reply/forward delivery tail, HTTP-free: |
| 1118 | // HITL hold (HoldForApprovalCore), else self-send loopback, else SES send + |
no test coverage detected