{"record":{"id":"dfde75f092832579","repo":"hcengineering/platform","slug":"from-is-missing","errorCode":null,"errorMessage":"'from' is missing","messagePattern":"'from' is missing","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"services/mail/pod-mail/src/main.ts","lineNumber":112,"sourceCode":"  const fromAddress = from ?? config.source\n  if (text === undefined && html === undefined) {\n    ctx.warn('Text and html are missing in email request', { from, to })\n    res.status(400).send({ err: \"'text' and 'html' are missing\" })\n    return\n  }\n  if (subject === undefined) {\n    ctx.warn('Subject is missing in email request', { from, to })\n    res.status(400).send({ err: \"'subject' is missing\" })\n    return\n  }\n  if (to === undefined) {\n    ctx.warn('To address is missing in email request', { from })\n    res.status(400).send({ err: \"'to' is missing\" })\n    return\n  }\n  if (fromAddress === undefined) {\n    ctx.warn('From address is missing in email request', { to })\n    res.status(400).send({ err: \"'from' is missing\" })\n    return\n  }\n  const message: SendMailOptions = {\n    from: fromAddress,\n    to,\n    subject,\n    text\n  }\n  // When sending system message, ensure we enable replying to a different domain as needed\n  if (config.replyTo !== undefined && fromAddress === config.source) {\n    message.replyTo = config.replyTo\n  }\n  if (html !== undefined) {\n    message.html = html\n  }\n  if (headers !== undefined) {\n    message.headers = headers\n  }","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/mail/pod-mail/src/main.ts#L94-L130","documentation":"The pod-mail service rejects a send-mail request with HTTP 400 because the 'from' address is absent. When the handler destructures the request body, fromAddress is undefined, so the service refuses to build a nodemailer SendMailOptions object. It logs a warning ('From address is missing in email request') and returns a structured error body instead of attempting delivery.","triggerScenarios":"POST to the mail endpoint with a body containing 'to' and 'subject' but no 'from' field, or a 'from' field explicitly set to null/undefined; also a request whose JSON body fails to parse so all fields default to undefined.","commonSituations":"Migrating from an older API version where the from address was configured server-side; forgetting that pod-mail requires a per-request sender rather than a default sender in config; template or mail-merge code that only fills recipient fields; sending with Content-Type not set to application/json so express body-parser leaves body empty.","solutions":["Add a non-empty 'from' field to the JSON request body, e.g. {\"from\":\"sender@example.com\",\"to\":\"rcpt@example.com\",\"subject\":\"hi\"}.","Verify the request Content-Type is application/json and the body actually parses (empty body means every field, including 'from', is undefined).","Set a default sender in the calling code so every mail request includes it (e.g. from: config.defaultSender) instead of relying on per-call input.","Check for typo'd field names like 'sender', 'fromAddress', or 'From' — the service looks for exactly 'from'."],"exampleFix":"// before\nawait fetch(mailUrl, { method: 'POST', body: JSON.stringify({ to, subject }) })\n// after\nawait fetch(mailUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ from: 'noreply@example.com', to, subject }) })","handlingStrategy":"validation","validationCode":"function canSendMail(body: unknown): body is { from: string; to: string; subject: string } {\n  const b = body as any\n  return typeof b?.from === 'string' && b.from.includes('@') && typeof b?.to === 'string' && typeof b?.subject === 'string'\n}\nif (!canSendMail(payload)) throw new Error('mail request must include non-empty from/to/subject')","typeGuard":"const isFromAddress = (v: unknown): v is string => typeof v === 'string' && v.includes('@')","tryCatchPattern":"const res = await fetch(mailUrl, opts)\nif (res.status === 400) {\n  const { err } = await res.json()\n  throw new Error(`Mail request rejected: ${err}`)\n}","preventionTips":["Centralize mail sending in one helper that always injects a default from address","Validate from/to with an email regex before calling the endpoint","Always send application/json so the body parses and fields are defined"],"tags":["http-400","validation","email","missing-field"],"backgroundTag":"missing-request-field","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}