{"record":{"id":"8a4c54dfa8e05463","repo":"ory/kratos","slug":"unable-to-dispatch-mail-delivery-because-upstream","errorCode":null,"errorMessage":"unable to dispatch mail delivery because upstream server replied with status code %d","messagePattern":"unable to dispatch mail delivery because upstream server replied with status code (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"courier/http_channel.go","lineNumber":121,"sourceCode":"\t}\n\t// Close the original body, not the NopCloser below: closing it returns\n\t// the connection to the pool and ends the otelhttp client span.\n\tdefer func(body io.ReadCloser) { _ = body.Close() }(res.Body)\n\tres.Body = io.NopCloser(io.LimitReader(res.Body, 1024))\n\n\tlogger := c.d.Logger().\n\t\tWithField(\"http_server\", c.requestConfig.URL).\n\t\tWithField(\"message_id\", msg.ID).\n\t\tWithField(\"message_nid\", msg.NID).\n\t\tWithField(\"message_type\", msg.Type).\n\t\tWithField(\"message_template_type\", msg.TemplateType).\n\t\tWithField(\"message_subject\", msg.Subject)\n\n\tif res.StatusCode >= 200 && res.StatusCode < 300 {\n\t\tlogger.Debug(\"Courier sent out mailer.\")\n\t\treturn nil\n\t}\n\n\terr = errors.Errorf(\n\t\t\"unable to dispatch mail delivery because upstream server replied with status code %d\",\n\t\tres.StatusCode,\n\t)\n\n\tbody, _ := io.ReadAll(res.Body)\n\tlogger.\n\t\tWithError(err).\n\t\tWithField(\"http_response_body\", string(body)).\n\t\tError(\"sending mail via HTTP failed.\")\n\n\treturn errors.WithStack(err)\n}\n\nfunc (c *httpChannel) tryPopulateHTMLBody(ctx context.Context, tmpl Template, td *httpDataModel) {\n\tif emailTmpl, ok := tmpl.(EmailTemplate); ok {\n\t\t// Only get the HTML body from the template; plaintext body comes from msg.Body\n\t\t// to maintain backward compatibility with existing behavior","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/ory/kratos/blob/b86338da04a040247a07f46100a86dcfb3875909/courier/http_channel.go#L103-L139","documentation":"The HTTP courier channel finished POSTing a message to the configured upstream URL and received a response with a status outside the 2xx range. The upstream delivery endpoint rejected the request; the status code is included in the error.","triggerScenarios":"Thrown at courier/http_channel.go:121 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the upstream server's logs for why it returned the non-success status","Verify the request URL, auth and payload format expected by the HTTP channel configuration","If the failure was transient (e.g. 502/503), let the courier retry the dispatch"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"b86338da04a040247a07f46100a86dcfb3875909","analyzedAt":"2026-09-07T15:58:15.934Z","contentChangedAt":"2026-09-07T15:58:15.934Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}