100 Commits
Author SHA1 Message Date
KM Koushik d2dc18feec fix: forward SMTP attachments (#405)
* fix: forward SMTP attachments

Entire-Checkpoint: 7d7cb24de113

* fix: redact SMTP attachment logs

Entire-Checkpoint: 0b350a0d62e6

* fix: redact SMTP email logs

Entire-Checkpoint: 05a0a1779c5e

* Revert "fix: redact SMTP email logs"

This reverts commit c3e6657c870a6a4b3768adb3e550c1ceda9ace2d.

Entire-Checkpoint: 0225a4ef8dee

* Revert "fix: redact SMTP attachment logs"

This reverts commit 31e51d2ca01f4590f95448f72f7629cbc34ccd54.

Entire-Checkpoint: ee934de340c7
2026-05-18 16:21:54 +10:00
KM Koushik 2eca312022 fix: resolve dependabot security alerts (#404) 2026-05-18 14:53:02 +10:00
KM Koushik aa7c234284 chore: remove Claude workflows (#403)
* fix: update Claude workflows

Entire-Checkpoint: ece952fb64ea

* chore: remove Claude workflows

Entire-Checkpoint: 3b66c252f834
2026-05-18 13:26:45 +10:00
KM Koushik dad2941971 chore: add Entire agent config (#402)
Entire-Checkpoint: 69bf47d06770
2026-05-18 10:38:23 +10:00
04d0f4b123 feat: support standard AWS env vars and default credential chain (#401)
* feat: support standard AWS env vars and default credential chain

Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.

Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.

Closes #316

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* refactor: extract shared getAwsCredentialOptions helper and add partial-config guard

- Move the credential spread logic into a single credentials.ts helper
  so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
  is set, preventing silent fallback to the default provider chain with a
  half-configured environment

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix: align AWS env vars in docker and docs

* fix: use alias import for AWS credentials helper

---------

Co-authored-by: purva <[email protected]>
Co-authored-by: Purva Kandalgaonkar <[email protected]>
2026-05-17 21:23:28 +10:00
KM Koushik b20f3b5d74 fix: keep paid limits during Stripe retries (#386) 2026-04-01 13:37:09 +11:00
KM Koushik bd78ed9ad9 feat: add Sayr bronze sponsor (#383)
* feat: add Sayr bronze sponsor

* fix: correct Sayr black logo URL

* update ui
2026-03-28 08:57:51 +11:00
KM Koushik eafbb53104 docs: add v1.9.x changelog entry (#382)
* docs: add v1.9.x highlights to changelog

* docs: refine v1.9.0 changelog entry

* docs: expand v1.9.0 changelog copy
2026-03-23 15:55:04 +11:00
KM Koushik 741b2b159f fix: restore centered dialog fade animation after tailwind v4 migration (#381) 2026-03-16 22:30:07 +11:00
KM Koushik b16eb201d2 Add 'tebayoso' profile link and image to README
Added a link and image for the user 'tebayoso' to the README.
2026-03-16 22:20:59 +11:00
KM Koushik da9d5acdb4 Update README to reflect webhook support status 2026-03-16 22:18:07 +11:00
KM Koushik 42e68bfc49 fix: type dashboard chart metric keys (#380) 2026-03-16 00:07:28 +11:00
KM Koushik 4307670822 feat: better dashboard chart (#378)
* dashbaord ui stuff

* graph stuff

* stuff
2026-03-15 18:28:17 +11:00
KM Koushik 9a306b1d59 feat: migrate workspace to Tailwind CSS v4 (#377)
* feat: migrate workspace to Tailwind CSS v4

* refactor: move Tailwind v4 setup to CSS directives
2026-03-15 07:10:37 +11:00
KM Koushik d7b196c0e3 fix: simplify domain verification emails (#376) 2026-03-14 08:22:16 +11:00
KM Koushik 689cb8b366 feat: automate domain verification follow-ups (#375)
* feat: automate domain verification follow-ups

* fix: harden domain verification notifications

* fix: skip unchanged first-run domain status emails

* fix: make domain cleanup resilient and status labels readable

* fix: clarify domain verification notification messaging
2026-03-14 01:19:44 +11:00
KM Koushik 3c2d37906e feat: add multi-domain filters to webhooks (#361)
* feat(webhooks): add multi-domain endpoint filtering

* test(webhooks): add domain filter router coverage

* fix(webhooks): apply domain filters only to domain-scoped events

* stuff

* stuff
2026-03-08 09:01:39 +11:00
KM Koushik 79f9049e40 docs: add campaign personalization guide (#374)
* docs: add campaign personalization guide

* docs: show best practices without accordions
2026-03-08 08:23:37 +11:00
KM Koushik 83cb0b24f7 feat: sync sdk contact book support (#373) 2026-03-08 00:59:40 +11:00
KM Koushik 33acd09d77 fix build 2026-03-08 00:15:34 +11:00
KM Koushik 62e0a1db88 feat: add contact-book variable registry for campaign personalization (#359)
* feat: add contact-book variable registry for campaign personalization

* test: include contact-book variables default in service expectation

* fix: address personalization review issues

* fix text

* fix: normalize contact variable access across contact flows

* stuff

* fix
2026-03-08 00:03:58 +11:00
KM Koushik d97e445ea0 fix: bump usesend-js version to 1.6.2 for npm publish (#372) 2026-03-04 22:09:58 +11:00
KM Koushik 991fcab764 fix: bump usesend-js version to 1.6.1 for npm publish (#371) 2026-03-04 09:52:43 +11:00
KM Koushik 73416dc481 fix(test): add redisKey to Redis mocks (#369)
* fix(test): mock redisKey in Redis test doubles

* fix(test): include BULL_PREFIX in redis mock
2026-03-02 08:43:29 +11:00
KM Koushik 69eeb2d96e fix: reset contact list page when filters change (#368) 2026-03-01 20:38:42 +11:00
KM Koushik 9e588e2e6b feat: submit contact add form with Cmd/Ctrl+Enter (#366) 2026-03-01 00:58:02 +11:00
e3e9635a5f feat: add customizable contact double opt-in flow (#350)
* feat: add customizable contact double opt-in flow

* test: add double opt-in service coverage

* fix: address review comments for double opt-in PR

- Make pending status conditional on doubleOptInEnabled flag
- Backfill legacy unsubscribeReason for reliable pending detection
- Add doubleOptInContent to contact book listing select
- Fix duplicate toast on DOI editor subject save failure
- Harden searchParams parsing against string[] values
- Make default DOI template use link mark for clickable URL
- Make public API create+update atomic via transaction
- Prevent contact upsert failure when DOI email send fails
- Fix empty string template variable replacement

Co-authored-by: opencode <[email protected]>

* fix: harden double opt-in confirmation safeguards

Preserve explicit unsubscribe intent in DOI flows and prevent confirmation links from re-subscribing opted-out contacts. Also sanitize subscribe-page error messaging and use timing-safe hash comparison for link verification.

* ui stuff

* fix: require doubleOptInUrl in double opt-in templates

* feat: add configurable from address for double opt-in emails

* feat: add resend confirmation flow for pending contacts

* fix: move subscribe confirmation to explicit POST flow

* test: add contact book public API endpoint coverage

* docs: add double opt-in documentation and update OpenAPI spec

Add a user guide for the double opt-in feature covering setup, contact
statuses, email customization, template variables, and best practices.
Update the OpenAPI spec to include doubleOptIn fields in all contactBook
request/response schemas.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: opencode <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-01 00:34:20 +11:00
KM Koushik edcd32a4ea fix: prevent premature webhook auto-disable and allow re-enable (#364)
* fix: prevent premature webhook auto-disable and allow re-enable

Use persisted failure counters when deciding auto-disable status and restore dashboard re-enable flow so webhooks are not deactivated unexpectedly after reset.

* fix: count webhook failures per failed call

Only increment consecutive failure counters after a call exhausts retries, while keeping the 30-call auto-disable threshold and stale-state protection.

* fix(docs): correct webhook SDK package name (#363)

* test: isolate webhook unit suite from mailer deps

Mock limit service in webhook unit tests so Vitest does not resolve team-service and mailer paths requiring usesend-js during CI.
2026-02-28 07:40:26 +11:00
KM Koushik 1c644740f2 fix(docs): correct webhook SDK package name (#363) 2026-02-28 07:15:04 +11:00
KM Koushik 0c9ebc86a3 fix: preserve reply-to metadata when duplicating campaigns (#357) 2026-02-23 12:06:33 +11:00
KM Koushik 61dfcee67d fix: enforce team scoping for campaign, contacts, and invites (#356)
* fix: enforce team-scoped lookups for campaign contacts and invites

* fix(test): mock domain service in campaign security test
2026-02-23 11:30:05 +11:00
KM Koushik f7a0d11758 Fix webhook documentation link in changelog
Updated webhook documentation link to point to the correct URL.
2026-02-22 23:28:15 +11:00
KM KoushikandClaude 091b99cb10 Add v1.8.0 changelog entry with February 2025 updates (#348)
* docs: add v1.8.0 changelog with features since v1.7.0

Adds changelog entry covering webhooks, Python SDK, Contact Books API,
email retention/cleanup, idempotency support, and various improvements.

https://claude.ai/code/session_012hGggJSKqRZB4PkaaPAyrS

* update

---------

Co-authored-by: Claude <[email protected]>
2026-02-22 22:19:41 +11:00
KM Koushik 487902421b feat: add web testing foundation with infra-backed suites (#349)
* feat: add web test framework with infra-backed suites

* fix: honor DATABASE_URL env in integration prepare script

* fix: apply web test review feedback

* fix: streamline web test infra lifecycle and workflow scope
2026-02-16 09:13:29 +11:00
KM KoushikandClaude 09bdb8aaad feat(python-sdk): add webhook verification and event handling (#344)
* feat(python-sdk): add webhook verification and event handling

Add webhook support to the Python SDK matching the JS SDK implementation:
- Add Webhooks class with verify() and construct_event() methods
- Implement HMAC-SHA256 signature verification with timing-safe comparison
- Add timestamp validation with configurable tolerance (default 5 minutes)
- Add comprehensive webhook event types (18 events: email, contact, domain, test)
- Add WebhookVerificationError with typed error codes
- Export webhook constants (headers) and types

* fix(python-sdk): harden webhook parsing and typing

Normalize invalid UTF-8 webhook payloads to INVALID_BODY errors so verify() safely returns false, and narrow base email webhook event types to avoid discriminated-union overlap. Add regression tests for both paths.

* chore(python-sdk): bump package version to 0.2.9

* feat(python-sdk): add local webhook test example project

Add a runnable Flask receiver and signed webhook sender under packages/python-sdk/example, and link it from the Python SDK README for local verification.

---------

Co-authored-by: Claude <[email protected]>
2026-02-08 08:18:14 +11:00
KM KoushikandClaude e246d32ef9 fix: prevent duplicate notification emails via atomic Redis SET NX (#346)
The warning and limit-reached notification emails were being sent
multiple times because of a race condition: concurrent workers could
both read the Redis cooldown key as empty (GET), both send emails,
then both set the key (SETEX). Replaced the non-atomic GET + SETEX
pattern with a single atomic SET ... NX EX that claims the cooldown
slot before any emails are sent. Also increased cooldown from 6 hours
to 24 hours so each notification is sent at most once per day.

https://claude.ai/code/session_01VBYXi5e64Vtq1cXWsfTYTw

Co-authored-by: Claude <[email protected]>
2026-02-01 07:24:02 +11:00
KM Koushik 1b3b8f5751 fix: add repository field for npm provenance 2026-01-18 22:08:26 +11:00
KM Koushik 4c4d150dba fix: configure npm OIDC trusted publishing correctly 2026-01-18 22:03:24 +11:00
KM Koushik b3b7bddafb Change publish command from pnpm to npm 2026-01-18 21:56:01 +11:00
KM Koushik b0575ea9fc Update release workflow with OIDC permissions
Added permissions for OIDC and updated job steps.
2026-01-18 21:54:08 +11:00
KM Koushik eed37d09c6 fix build 2026-01-18 21:44:25 +11:00
KM Koushik d3b6ba7c0a fix: add tsup config for SDK and bump version to 1.6.0 (#343) 2026-01-18 21:04:43 +11:00
KM Koushik 8676965019 feat: add webhooks (#334) 2026-01-18 20:50:54 +11:00
KM Koushik f40a311cc9 fix: enforce contact book ownership (#341) 2026-01-17 18:08:05 +11:00
KM Koushik bba9e937bb fix seg fault (#329) 2025-12-30 07:45:34 +11:00
KM KoushikandClaude 95dfa6b532 Upgrade Next.js to 15.5.9 (#326)
Co-authored-by: Claude <[email protected]>
2025-12-18 06:48:24 +11:00
KM Koushik bef580ff92 use turbo in dev mode (#321) 2025-12-14 20:29:53 +11:00
KM KoushikandClaude 11b5ac1bf7 Fix bar chart hover on zero delivery days (#320)
Co-authored-by: Claude <[email protected]>
2025-12-14 10:27:28 +11:00
KM Koushik 1e79f13bd4 add export contact book option (#318) 2025-12-14 10:08:54 +11:00
KM KoushikandClaude 461cd949e5 Fix Infinity% display bug in email chart (#319)
Co-authored-by: Claude <[email protected]>
2025-12-14 09:35:05 +11:00
KM Koushik fd3c600b2e add upload contacts support (#314) 2025-12-13 08:15:42 +11:00
KM KoushikandClaude 7fdb82a9e9 Fix version display in side navigation (#306)
Co-authored-by: Claude <[email protected]>
2025-12-08 09:19:37 +11:00
KM KoushikandClaude 3e3f6d521a Display Docker image version in sidebar (#304)
Co-authored-by: Claude <[email protected]>
2025-12-07 22:18:56 +11:00
KM Koushik b4640ac5e4 update mintlify (#302) 2025-12-07 07:48:33 +11:00
KM Koushik 693ec9c0ce bump nextjx version (#301) 2025-12-07 07:41:15 +11:00
KM Koushik d6be1af5b9 fix image position issue 2025-12-04 08:24:06 +11:00
KM Koushik e1b64d0d7b Add feedback dialog for cloud dashboard (#293) 2025-11-29 10:22:12 +11:00
KM Koushik 05a02844b2 Update prisma version in start script 2025-11-21 20:14:05 +11:00
KM Koushik b2e0233758 fix: update docker node version (#290) 2025-11-20 18:08:07 +11:00
KM Koushik cb489654b5 idempotency (#282) 2025-11-17 11:42:09 +11:00
KM Koushik f525381fb9 send free limit reached email for inactive plans 2025-10-26 11:05:51 +11:00
KM KoushikandClaude 7edff5b783 Add subscription ID search to admin team lookup (#284)
Co-authored-by: Claude <[email protected]>
2025-10-26 09:40:11 +11:00
KM KoushikandClaude 4fe354b85a Fix free limits and email notifications for inactive users (#283)
Co-authored-by: Claude <[email protected]>
2025-10-26 07:52:44 +11:00
KM Koushik 8e569f886e fix build 2025-10-25 05:43:00 +11:00
KM KoushikandClaude 1c9056ba75 Configure Email Usage Alert Logic (#278)
Co-authored-by: Claude <[email protected]>
2025-10-25 05:37:46 +11:00
KM Koushik 374f173a09 add delete resource modal (#280) 2025-10-25 05:37:16 +11:00
KM KoushikandClaude f1e63b6c46 add team ID column to email analytics page (#279)
Co-authored-by: Claude <[email protected]>
2025-10-25 04:49:45 +11:00
KM Koushik 77b0239b92 add contact to users on waitlist removal (#276) 2025-10-19 15:08:33 +11:00
KM Koushik 78db758512 product update 2025-10-19 08:15:04 +11:00
KM Koushik 189b44bc1e fix campaign update not working 2025-10-19 07:14:03 +11:00
KM Koushik 367457997e add changelog page (#275) 2025-10-19 06:57:23 +11:00
KM Koushik a5ca3b2f87 add campaign api (#274) 2025-10-18 10:31:43 +11:00
KM Koushik e631f16c85 feat: batch campaigns (#227) 2025-10-12 22:43:16 +11:00
KM Koushik 159b15e37e queue bulk contacts (#273) 2025-10-12 06:18:04 +11:00
KM Koushik 2fe2d5cdab update package version and response return tyupe for delete domain api (#272) 2025-10-11 06:37:24 +11:00
KM Koushik 890ad72057 feat: add custom email headers (#260) 2025-09-28 21:33:45 +10:00
KM Koushik 1a00999bf0 feat: add waitlist rejection email (#257) 2025-09-27 09:41:47 +10:00
KM Koushik 76fdad6c81 feat: expose domain dns records via api (#259) 2025-09-27 09:40:14 +10:00
KM Koushik 014199201b fix: clear email attachments after send (#258) 2025-09-27 06:30:33 +10:00
KM Koushik b342335502 add coderabbit as sponsor (#256) 2025-09-26 07:37:05 +10:00
KM Koushik 5780177d26 fix: send founder email on first paid subscription (#247) 2025-09-21 06:18:16 +10:00
KM Koushik 1226e89aaf add postmortem (#241) 2025-09-19 22:09:54 +10:00
KM Koushik 2fa8c1b600 fix build 2025-09-19 08:24:08 +10:00
KM Koushik 81faba2aba add admin mail analytics (#240) 2025-09-19 08:18:23 +10:00
KM Koushik 62a15ef811 add waitlist confirmation (#239) 2025-09-19 07:26:38 +10:00
KM Koushik 87c772dcc4 add waitlist submission form (#238) 2025-09-18 21:00:59 +10:00
KM Koushik 21cac61d89 docs: clarify anti-spam requirements (#236) 2025-09-18 03:30:12 +10:00
KM Koushik c9114be223 docs: add anti-spam enforcement clause to terms (#235) 2025-09-18 02:53:14 +10:00
KM Koushik 4144c75959 Enforce unsub url 2025-09-18 02:14:24 +10:00
KM Koushik e1cb1f27d1 enable waitlisting in cloud 2025-09-17 22:13:03 +10:00
KM Koushik 8c8af1f846 use bucket from environment variable 2025-09-17 18:08:57 +10:00
KM Koushik c8ef49f12c fix callback not working in self-hosted version (#234) 2025-09-17 17:38:12 +10:00
KM Koushik cbd97853b9 docs: update railway deploy links (#233) 2025-09-16 07:45:01 +10:00
KM Koushik 4c4094619a docs: remove MCP contextual options (#229) 2025-09-15 05:30:58 +10:00
KM Koushik 101bcc56b1 Update open_collective funding format 2025-09-14 07:41:52 +10:00
KM Koushik c440a7111a Add Open Collective funding option 2025-09-14 07:40:56 +10:00
KM Koushik 053fafb7cd docs: add Railway self-hosting guide (#228) 2025-09-14 06:34:11 +10:00
KM Koushik 0872179762 fix: update domain name in the dns records 2025-09-12 06:49:16 +10:00
KM Koushik 66208a4b7a chore: update README with new contributors and remove outdated Python documentation 2025-09-11 21:09:06 +10:00
KM Koushik 59fac64356 add simpleanalytics 2025-09-11 10:40:10 +10:00