Skip to content

Add live smoke testing for email providers#21

Open
leoisadev1 wants to merge 1 commit into
mainfrom
t3code/e59d1989
Open

Add live smoke testing for email providers#21
leoisadev1 wants to merge 1 commit into
mainfrom
t3code/e59d1989

Conversation

@leoisadev1
Copy link
Copy Markdown
Member

Summary

  • Add a new live:smoke script and src/live-smoke.ts CLI to validate provider configuration and optionally send live test emails.
  • Add a live environment example file with provider-specific sender and API key variables for smoke testing.
  • Record live verification status for each provider and surface it in the Fumadocs provider catalog with verified/untested badges and notes.
  • Document the current verified Resend scope in live-verification.json.

Testing

  • Not run (not requested).
  • Added a dry-run path that prints a JSON summary without sending mail unless --send is passed.
  • Added provider-specific env checks so missing credentials or sender addresses are reported before attempting delivery.
  • Verified the UI changes update provider cards/badges to reflect live verification status and notes.

- Document live verification status in the provider catalog
- Add env example, verification manifest, and smoke test runner
@vercel
Copy link
Copy Markdown

vercel Bot commented May 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
email-sdk-fumadocs Ready Ready Preview, Comment May 30, 2026 12:19pm

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 30, 2026

Greptile Summary

This PR introduces a live:smoke CLI (src/live-smoke.ts) that validates provider credentials and optionally sends real test emails, alongside a live-verification.json record and UI badges in the Fumadocs provider catalog showing verified/untested status per provider.

  • live-smoke.ts — new Bun CLI that iterates all 14 adapters, checks required env vars, and either dry-runs or sends a test message; exits with code 1 on any non-skipped failure.
  • provider-catalog.tsx / providers.ts — each provider entry gains a verification object (status + note) surfaced as a coloured pill (VerificationPill) in the grid and badge components.
  • .env.live.example / live-verification.json — companion files documenting required env vars and the current verification state of each provider.

Confidence Score: 4/5

Safe to merge after fixing the hardcoded personal email fallback in live-smoke.ts and .env.live.example.

The smoke runner is well-structured — it checks env vars before attempting sends, exits non-zero on failures, and the dry-run path is safe. The one real concern is that the default to address is a personal Gmail; any contributor running --send without LIVE_EMAIL_TO set will silently deliver live mail to that inbox. The UI and data changes in providers.ts and provider-catalog.tsx are straightforward and carry no functional risk.

packages/email-sdk/src/live-smoke.ts (line 33) and packages/email-sdk/.env.live.example (line 4) — both contain the hardcoded personal email address that acts as the live-send recipient fallback.

Important Files Changed

Filename Overview
packages/email-sdk/src/live-smoke.ts New CLI smoke-test runner — hardcodes a personal Gmail address as the fallback to recipient, which will silently send live emails to that address if LIVE_EMAIL_TO is not set. Also calls new Date() twice independently in buildMessage, producing potentially mismatched timestamps in text and HTML bodies.
packages/email-sdk/.env.live.example Example env file ships with LIVE_EMAIL_TO pre-populated with a personal email address, propagating the hardcoded-recipient problem into copy-paste usage.
apps/fumadocs/src/components/provider-catalog.tsx Adds VerificationPill component and updates ProviderBadge/ProviderGrid to surface verification status. Minor: className merging uses template-string concatenation instead of a utility like cn().
apps/fumadocs/src/lib/providers.ts Adds verification: { status, note } to every provider entry — straightforward data addition, no issues found.
packages/email-sdk/live-verification.json New JSON record of live-verification outcomes per provider — documentation artefact, no code issues.
packages/email-sdk/package.json Adds live:smoke script pointing at src/live-smoke.ts via bun run — straightforward, no issues.

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant CLI as live-smoke.ts
    participant Env as process.env / flags
    participant Adapter as EmailAdapter
    participant Provider as Email Provider API

    Dev->>CLI: bun run live:smoke [--send] [--adapter X] [--from addr]
    CLI->>Env: resolve `to`, `from`, credentials per adapter
    alt missing env vars
        CLI-->>Dev: "results[].skipped = true (no send)"
    else dry-run (no --send)
        CLI-->>Dev: "results[].sent = false"
    else --send mode
        CLI->>Adapter: provider.create()
        CLI->>Adapter: "createEmailClient({ adapters })"
        Adapter->>Provider: HTTP send request
        Provider-->>Adapter: response / error
        Adapter-->>CLI: EmailProviderResponse
        CLI-->>Dev: JSON summary (redacted response)
    end
    CLI->>Dev: process.exit(1) if any non-skipped failure
Loading

Fix All in Claude Code

Reviews (1): Last reviewed commit: "Add live smoke testing for email provide..." | Re-trigger Greptile

const flags = parseFlags(Bun.argv.slice(2));
const sendLive = truthyFlag("send");
const selectedAdapters = selectedAdapterNames();
const to = stringFlag("to") ?? process.env.LIVE_EMAIL_TO ?? "leodoesdev@gmail.com";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hardcoded personal email as the default recipient

Any contributor who runs bun run live:smoke -- --send without exporting LIVE_EMAIL_TO will silently deliver live test emails to a personal Gmail address. The same address is also pre-filled in .env.live.example (line 4), so copy-paste usage inherits it. The fallback should require an explicit value — throw if neither --to nor LIVE_EMAIL_TO is set — rather than quietly routing real email to someone's inbox. Confidence: 5/5

Fix in Claude Code

Comment on lines +213 to +222
text: [
"Email SDK live smoke test.",
`Adapter: ${adapter}`,
`Timestamp: ${new Date().toISOString()}`,
].join("\n"),
html: [
"<p>Email SDK live smoke test.</p>",
`<p><strong>Adapter:</strong> ${escapeHtml(adapter)}</p>`,
`<p><strong>Timestamp:</strong> ${escapeHtml(new Date().toISOString())}</p>`,
].join(""),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 new Date() is called separately for the text and html bodies, so the two timestamps can diverge by a millisecond or more on a slow machine. Capture it once and share the value. Confidence: 3/5

Suggested change
text: [
"Email SDK live smoke test.",
`Adapter: ${adapter}`,
`Timestamp: ${new Date().toISOString()}`,
].join("\n"),
html: [
"<p>Email SDK live smoke test.</p>",
`<p><strong>Adapter:</strong> ${escapeHtml(adapter)}</p>`,
`<p><strong>Timestamp:</strong> ${escapeHtml(new Date().toISOString())}</p>`,
].join(""),
text: [
"Email SDK live smoke test.",
`Adapter: ${adapter}`,
`Timestamp: ${new Date().toISOString()}`,
].join("\n"),
html: (() => {
const ts = escapeHtml(new Date().toISOString());
return [
"<p>Email SDK live smoke test.</p>",
`<p><strong>Adapter:</strong> ${escapeHtml(adapter)}</p>`,
`<p><strong>Timestamp:</strong> ${ts}</p>`,
].join("");
})(),

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Comment on lines +66 to +82
if (status === "verified") {
return (
<span
className={`mt-3 inline-flex w-fit rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300 ${className ?? ""}`}
>
Live verified
</span>
);
}

return (
<span
className={`mt-3 inline-flex w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2 py-0.5 text-[11px] font-medium text-amber-800 dark:text-amber-300 ${className ?? ""}`}
>
Untested live
</span>
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The VerificationPill component concatenates className via a template string (${className ?? ""}). If className is undefined the span gets a trailing space in its class attribute. The rest of the codebase likely uses a cn() / clsx() utility — prefer that pattern to avoid potential whitespace issues. Confidence: 2/5

Suggested change
if (status === "verified") {
return (
<span
className={`mt-3 inline-flex w-fit rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300 ${className ?? ""}`}
>
Live verified
</span>
);
}
return (
<span
className={`mt-3 inline-flex w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2 py-0.5 text-[11px] font-medium text-amber-800 dark:text-amber-300 ${className ?? ""}`}
>
Untested live
</span>
);
if (status === "verified") {
return (
<span
className={[
"mt-3 inline-flex w-fit rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300",
className,
]
.filter(Boolean)
.join(" ")}
>
Live verified
</span>
);
}
return (
<span
className={[
"mt-3 inline-flex w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2 py-0.5 text-[11px] font-medium text-amber-800 dark:text-amber-300",
className,
]
.filter(Boolean)
.join(" ")}
>
Untested live
</span>
);

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant