feat(sendgrid): transactional email integration (#18)#76
Open
jackulau wants to merge 2 commits into
Open
Conversation
Adds @jam-nodes/nodes SendGrid integration with three nodes:
- sendgridSendEmailNode — POST /v3/mail/send (template + attachment support, x-message-id header)
- sendgridCreateContactNode — PUT /v3/marketing/contacts (upsert; returns job_id)
- sendgridGetContactsNode — POST /v3/marketing/contacts/search (SGQL filter, 50/call cap, client-side limit/offset)
Also extends @jam-nodes/core NodeCredentials with a sendgrid?: { apiKey } entry
and registers the new exports in packages/nodes/src/integrations/index.ts.
48 unit tests cover credential metadata, schema validation, all happy paths,
template/attachment handling, SGQL escaping, error responses, and 401 auth
failures. Full nodes test suite goes from 195 -> 243 with no regressions.
Closes wespreadjam#18
- Add Zod superRefine: dynamicTemplateData requires templateId - Block CRLF characters in subject (defense-in-depth header injection guard) - Trim trailing whitespace on all email fields before .email() validation - Cover attachment disposition/content_id mapping in tests - Cover SGQL backslash escaping in tests (single quote, backslash, and \\' edge case) Test count 48 -> 54 (243 -> 249 across the nodes package).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #18.
Adds a SendGrid transactional email integration to
@jam-nodes/nodeswith three new nodes, an API-key credential, full Zod schemas, and a comprehensive Vitest suite. Follows the established Slack integration pattern (packages/nodes/src/integrations/slack/) end-to-end.What changed
New files
packages/nodes/src/integrations/sendgrid/credentials.ts—defineApiKeyCredentialwith header authAuthorization: Bearer {{apiKey}}.packages/nodes/src/integrations/sendgrid/schemas.ts— input/output Zod schemas for all three operations, plus sharedSendgridContentSchema,SendgridAttachmentSchema,SendgridContactSchema.packages/nodes/src/integrations/sendgrid/sendgrid-send-email.ts—sendgridSendEmailNode(POST /v3/mail/send).packages/nodes/src/integrations/sendgrid/sendgrid-create-contact.ts—sendgridCreateContactNode(PUT /v3/marketing/contacts, upsert).packages/nodes/src/integrations/sendgrid/sendgrid-get-contacts.ts—sendgridGetContactsNode(POST /v3/marketing/contacts/search, SGQL).packages/nodes/src/integrations/sendgrid/index.ts— barrel export.packages/nodes/src/integrations/sendgrid/__tests__/sendgrid.test.ts— 54 unit tests.Modified files
packages/core/src/types/node.ts— addssendgrid?: { apiKey: string }toNodeCredentials.packages/nodes/src/integrations/index.ts— re-exports the new nodes, schemas, types, and credential.Design notes
fetchWithRetry; retry / cache / timeout cross-cutting concerns stay in the execution engine per the architectural rule inCLAUDE.md(Issue feat: add execution engine with configurable retry, caching, and timeout #37, PR feat: add an execution engine with configurable retry, caching, and timeout #39).defineApiKeyCredential, mirroringdevto/credentials.ts.x-message-idheader is the only signal SendGrid returns from/v3/mail/send(the body is empty on202); the executor reads it from response headers and falls back to an empty string when absent.PUT /v3/marketing/contactsis SendGrid's upsert endpoint — the executor surfaces the returnedjob_idascontactJobIdso callers can poll job status.POST /v3/marketing/contacts/searchis the only contacts endpoint that supportslistIdfiltering. The executor builds an SGQL query with single-quote and backslash escaping to prevent SGQL injection. Results are capped at 50 per call by SendGrid;limit/offsetare applied client-side andtotalreflectscontact_countfrom the response.templateIdstrips top-levelcontentbefore sending (SendGrid rejects requests that include both).superRefinerejectsdynamicTemplateDatawithouttemplateIdso callers get an immediate validation error instead of a silent drop.subjectblocks\\r/\\nas a defense-in-depth guard against header injection..email()validation so callers don't get opaque 400s from SendGrid for trailing whitespace.Verification
The pre-existing typecheck errors in
slack-send-message.ts/slack-update-message.ts/apify/google-sheetson `main` are unchanged — fixing them is out of scope for this issue.Acceptance criteria (from #18)