feat: Resend inbound client and webhook endpoint (#149) #155
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Relates to #149
Scope
Create the webhook endpoint for receiving Resend inbound emails and the client for fetching email content.
Webhook Endpoint
POST /api/webhooks/resend/inbound(public, no JWT auth)rawBody: trueconfig for signature verificationresend.webhooks.verify()email_ingestion_queuerow with status=pendingsetImmediate()Resend Inbound Client
ResendInboundClientclass inexternal/resend-inbound.client.tsgetEmail(emailId): Callresend.emails.receiving.get()to get raw.download_urldownloadRawEmail(downloadUrl): Download raw RFC 5322 emailparseEmail(rawEmail): Parse withmailparserto extract body text/html + attachmentsRoute Registration
app.tsalongside existing webhook routesEnvironment
RESEND_WEBHOOK_SECRETenv var for signature verificationFiles
backend/src/features/email-ingestion/api/email-ingestion.routes.tsbackend/src/features/email-ingestion/api/email-ingestion.controller.tsbackend/src/features/email-ingestion/external/resend-inbound.client.tsbackend/src/features/email-ingestion/index.tsDependencies
mailparser+@types/mailparserAcceptance Criteria
Milestone: Resend Inbound Webhook Endpoint and Client
Phase: Execution | Agent: Developer | Status: PASS
Completed
Webhook Endpoint (
POST /api/webhooks/resend/inbound):svix-id,svix-timestamp,svix-signatureheadersemail_identriesemail_ingestion_queuerow with status=pendingsetImmediate()ResendInboundClient (
external/resend-inbound.client.ts):verifyWebhookSignature(): Svix webhook verificationgetEmail(emailId): Fetches email metadata from Resend APIdownloadRawEmail(downloadUrl): Downloads raw RFC 5322 email contentparseEmail(rawEmail): Parses with mailparser into text/html + attachmentsConfig (
config-loader.ts):resend_webhook_secret(optional) to secrets schemagetResendConfig()convenience accessorRESEND_WEBHOOK_SECRETset from secret fileRoute Registration (
app.ts):emailIngestionWebhookRoutesalongside Stripe webhooksemail-ingestionto health check feature listDependencies:
mailparser+@types/mailparserfor RFC 5322 parsingsvixfor Resend webhook signature verificationValidation
anytype warnings matching existing patterns)Files Changed
backend/src/features/email-ingestion/api/email-ingestion.routes.ts(new)backend/src/features/email-ingestion/api/email-ingestion.controller.ts(new)backend/src/features/email-ingestion/external/resend-inbound.client.ts(new)backend/src/features/email-ingestion/index.ts(new)backend/src/app.ts(modified - route registration)backend/src/core/config/config-loader.ts(modified - resend webhook secret)backend/package.json(modified - new dependencies)Verdict: PASS | Next: Async processing pipeline (sender validation, OCR, record creation)