{"record":{"id":"d97969d68ad5c19f","repo":"ory/kratos","slug":"courier-email-recipient-is-not-a-valid-email-addr","errorCode":null,"errorMessage":"courier: email recipient is not a valid email address","messagePattern":"courier: email recipient is not a valid email address","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"courier/smtp.go","lineNumber":116,"sourceCode":"\tcase \"smtps\":\n\t\tdialer.TLSConfig = tlsConfig\n\t\tdialer.SSL = true\n\t}\n\n\treturn &SMTPClient{\n\t\tDialer: dialer,\n\t}, nil\n}\n\nfunc (c *courier) QueueEmail(ctx context.Context, t EmailTemplate) (uuid.UUID, error) {\n\trecipient, err := t.EmailRecipient()\n\tif err != nil {\n\t\treturn uuid.Nil, errors.WithStack(err)\n\t}\n\t// The RFC 5322 fallback keeps previously-valid addresses working; the\n\t// address is not included in the error because it is identity PII.\n\tif _, err := stdmail.ParseAddress(recipient); err != nil && !x.IsEmailAddress(recipient) {\n\t\treturn uuid.Nil, errors.New(\"courier: email recipient is not a valid email address\")\n\t}\n\n\tsubject, err := t.EmailSubject(ctx)\n\tif err != nil {\n\t\treturn uuid.Nil, errors.WithStack(err)\n\t}\n\n\tbodyPlaintext, err := t.EmailBodyPlaintext(ctx)\n\tif err != nil {\n\t\treturn uuid.Nil, errors.WithStack(err)\n\t}\n\n\ttemplateData, err := json.Marshal(t)\n\tif err != nil {\n\t\treturn uuid.Nil, errors.WithStack(err)\n\t}\n\n\trequestHeaders := []byte(`{}`)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/ory/kratos/blob/b86338da04a040247a07f46100a86dcfb3875909/courier/smtp.go#L98-L134","documentation":"QueueEmail (courier/smtp.go:116) validates the email recipient before queuing: it must parse as an RFC 5322 address or match the library's IsEmailAddress check. The error message deliberately excludes the address because it is identity PII. A malformed recipient on a mail courier message aborts queuing and returns uuid.Nil.","triggerScenarios":"Enqueueing a courier email template message whose recipient field is an empty string, a username without domain, contains spaces/invalid characters, or is otherwise not a valid email; identity verifications or recovery flows with a corrupted identity's contact address.","commonSituations":"Identities imported via CSV/API with `email` traits that are not real addresses (e.g. 'jane', 'jane@@x', trailing whitespace/newlines); upstream systems writing invalid values into the identity traits.","solutions":["Fix the identity's email trait (via API: PUT /admin/identities/{id}) to a valid address and retry the flow","Validate/normalize emails at identity-creation time (schema `format: email` on the trait)","Check for leading/trailing whitespace or hidden characters in the stored address and trim them","If the address is intentionally nonstandard, use an RFC 5322 compliant form (e.g. `\"Name\" <a@b.com>` is fine; bare invalid strings are not)"],"exampleFix":"// before\n{\"traits\": {\"email\": \"jane.doe@\"}}\n// after\n{\"traits\": {\"email\": \"jane.doe@example.com\"}}","handlingStrategy":"validation","validationCode":"func validEmail(s string) bool {\n  _, err := net/mail.ParseAddress(strings.TrimSpace(s))\n  return err == nil\n}\n// guard before enqueueing courier email\nif !validEmail(identity.Traits[\"email\"]) { /* fix or reject */ }","typeGuard":"func isEmailAddress(s string) bool {\n  s = strings.TrimSpace(s)\n  if s == \"\" { return false }\n  _, err := net/mail.ParseAddress(s)\n  return err == nil && strings.Contains(s, \"@\")\n}","tryCatchPattern":null,"preventionTips":["Enforce `format: email` in the identity JSON schema so invalid emails are rejected at registration","Sanitize/trim email traits when importing identities via API or CSV","Periodically audit identities for invalid contact addresses using the admin API","Remember the error hides the address (PII); check server logs/identity data to find the offender"],"tags":["email","validation","courier"],"backgroundTag":"invalid-identifier-format","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"}