Skip to content

Commit

Permalink
Remove resend, use Postmark
Browse files Browse the repository at this point in the history
Resend has been plagued with security issues lately, and I can no
longer recommend using them for production apps, especially ones which
send authentication links via email.

Postmark has been a leader in the space for a long time and is one of
the easiest and most reliable email services to use.
  • Loading branch information
venables committed Feb 24, 2024
1 parent 92c68c1 commit f8d0673
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 24 deletions.
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ AUTH_GOOGLE_SECRET=
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=

# Email (https://resend.com)
# Email (https://postmarkapp.com)
EMAIL_FROM="StartKit <hello@startkit.dev>"
RESEND_API_KEY=
POSTMARK_API_KEY=
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
- [TailwindCSS](https://tailwindcss.com/) for utility-first CSS.
- Gorgeous UI built with [Radix](https://www.radix-ui.com/) and [shadcn/ui](https://ui.shadcn.com/).
- Authentication via [Next Auth](https://next-auth.js.org/) version 5.
- Email via [Resend](https://resend.com) and [react email](https://react.email/).
- Email via [Postmark](https://postmarkapp.com) and [jsx-email](https://jsx.email/).
- The beautiful [Geist](https://vercel.com/font) typeface.
- [Next Metadata API](https://beta.nextjs.org/docs/api-reference/metadata) for SEO handling, with file-system handlers.
- [Jest](https://jestjs.io/) testing, optimized for Next.js
Expand Down Expand Up @@ -125,7 +125,7 @@ bun run db studio

## Email

Email is currently configured to send via [Resend](https://resend.com), and uses the wonderful [jsx-email](https://jsx.email) library.
Email is configured to send via the amazing [Postmark](https://postmarkapp.com) email service, and uses the wonderful [jsx-email](https://jsx.email) library.

Email templates live with your react code and are defined in [`./emails`](./emails).

Expand Down
2 changes: 1 addition & 1 deletion app/(marketing)/features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function Features() {
{ title: "TailwindCSS", href: "https://tailwindcss.com" },
{ title: "Radix UI", href: "https://www.radix-ui.com" },
{ title: "PostgreSQL" },
{ title: "Email via Resend", href: "https://resend.com" },
{ title: "Email via Postmark", href: "https://postmarkapp.com" },
{ title: "Vercel ready", href: "https://vercel.com" },
{ title: "Metadata SEO" },
{ title: "Geist Font", href: "https://vercel.com/font" },
Expand Down
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion env/env.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const env = createEnv({
* Email
*/
EMAIL_FROM: z.string(),
RESEND_API_KEY: z.string().optional()
POSTMARK_API_KEY: z.string().default("")
},
/**
* Shared between server and client
Expand Down
6 changes: 3 additions & 3 deletions lib/auth/send-verification-request.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { usersTable } from "@/drizzle/schema"
import { Template as SignInEmail } from "@/emails/signin-email"
import { env } from "@/env"
import { db } from "@/lib/db"
import { emailClient } from "@/lib/email"
import { sendEmail } from "@/lib/email/send-email"

type SendVerificationRequestParams = Parameters<
EmailConfig["sendVerificationRequest"]
Expand Down Expand Up @@ -36,9 +36,9 @@ export async function sendVerificationRequest({
const html = await render(template)
const text = await render(template, { plainText: true })

await emailClient().emails.send({
from: env.EMAIL_FROM,
await sendEmail({
to: email,
from: env.EMAIL_FROM,
headers: {
"X-Entity-Ref-ID": Date.now().toString()
},
Expand Down
13 changes: 0 additions & 13 deletions lib/email/client.ts

This file was deleted.

1 change: 0 additions & 1 deletion lib/email/index.ts

This file was deleted.

53 changes: 53 additions & 0 deletions lib/email/send-email.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { env } from "@/env"

export type SendEmailParams = {
to: string
from: string
subject: string
html?: string
text?: string
headers?: Record<string, string>
}

/**
* Sends an email using Postmark's API.
*
* @see {@link https://postmarkapp.com/developer/user-guide/send-email-with-api}
*/
export async function sendEmail({
to,
from,
subject,
html,
text,
headers
}: SendEmailParams) {
const response = await fetch("https://api.postmarkapp.com/email", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"X-Postmark-Server-Token": env.POSTMARK_API_KEY
},
body: JSON.stringify({
From: from,
To: to,
Subject: subject,
HtmlBody: html,
TextBody: text,
MessageStream: "outbound",
Headers:
headers &&
Object.entries(headers).map(([key, value]) => ({
Name: key,
Value: value
}))
})
})

if (!response.ok) {
throw new Error(`Email send failed: ${response.status}`)
}

return response.json()
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.50.1",
"resend": "^3.2.0",
"sonner": "^1.4.1",
"tailwind-merge": "^2.2.1",
"typed-route-handler": "^0.1.1",
Expand Down

0 comments on commit f8d0673

Please sign in to comment.