{"record":{"id":"98519e435a71a177","repo":"hcengineering/platform","slug":"invalid-email-address","errorCode":null,"errorMessage":"Invalid email address","messagePattern":"Invalid email address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"services/mail/mail-common/src/utils.ts","lineNumber":243,"sourceCode":"  if (messageId !== undefined) {\n    headers[HulyMessageIdHeader] = messageId\n  }\n  return headers\n}\n\nexport function isHulyMessage (headers: string[]): boolean {\n  return headers.some(\n    (header) =>\n      header.startsWith(HulyMailHeader) ||\n      header.startsWith(HulyMessageIdHeader) ||\n      header.startsWith(HulyMessageTypeHeader)\n  )\n}\n\nexport function getDomainFromEmail (email: string): string {\n  const atIndex = email.lastIndexOf('@')\n  if (atIndex === -1) {\n    throw new Error('Invalid email address')\n  }\n  return email.substring(atIndex + 1)\n}\n\nexport function getEmailMessageIdFromHulyId (hulyId: string | undefined, email: string): string {\n  const domain = getDomainFromEmail(email)\n  const id = hulyId ?? generateMessageId()\n  return `<${id}@${domain}>`\n}\n\nexport function getHulyIdFromEmailMessageId (messageId: string, email: string): MessageID | undefined {\n  const domain = getDomainFromEmail(email)\n\n  const cleanMessageId = messageId.replace(/^<|>$/g, '')\n\n  const domainSuffix = `@${domain}`\n  if (!cleanMessageId.endsWith(domainSuffix)) {\n    return undefined","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/mail/mail-common/src/utils.ts#L225-L261","documentation":"getDomainFromEmail extracts the domain substring after the last '@' in an email. If the string contains no '@' at all (atIndex === -1), it throws this Error because the input is not a usable email address and no domain can be derived.","triggerScenarios":"Calling getDomainFromEmail (directly or viagetEmailMessageIdFromHulyId/domain helpers) with a string lacking '@' — e.g. a bare username, empty string, a display name, or an 'undisclosed-recipients' placeholder.","commonSituations":"Parsing inbound mail with malformed From/To headers; addresses stripped of their domain by upstream parsing; placeholder addresses like 'undisclosed-recipients:;' in mailing-list traffic; user-typed emails with typos ('userexample.com').","solutions":["Validate the email contains '@' before calling, e.g. email.includes('@') or a regex check.","Fix upstream header parsing so the extracted address includes its domain part.","Wrap the call in try/catch and treat the message as unprocessable rather than crashing ingestion.","Trim/clean the address (remove angle brackets like <user@host>) before domain extraction."],"exampleFix":"// before\nconst domain = getDomainFromEmail(fromHeader)\n// after\nconst addr = fromHeader.match(/<([^>]+)>/)?.[1] ?? fromHeader\nif (!addr.includes('@')) throw new Error(`Bad address: ${addr}`)\nconst domain = getDomainFromEmail(addr)","handlingStrategy":"type-guard","validationCode":"if (typeof email !== 'string' || !email.includes('@')) {\n  throw new Error(`Cannot extract domain from invalid email: ${email}`)\n}","typeGuard":"function isEmailAddress(s: unknown): s is string {\n  return typeof s === 'string' && s.includes('@') && s.lastIndexOf('@') < s.length - 1\n}","tryCatchPattern":"try {\n  domain = getDomainFromEmail(addr)\n} catch (err) {\n  if (err.message === 'Invalid email address') {\n    console.warn(`Unprocessable address \"${addr}\", skipping`)\n    domain = null\n  } else throw err\n}","preventionTips":["Extract addresses from mail headers with a regex that captures user@host inside angle brackets.","Validate emails at ingestion boundaries, before domain-dependent processing.","Reject or special-case placeholder addresses ('undisclosed-recipients:;') early."],"tags":["mail","validation","parsing","email"],"backgroundTag":"invalid-email-address","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}