How to create a simple email form with Cloudflare Pages and Resend
PDF Pals is a Mac app and it would be awkward to ask visitors to download on a mobile device.
So I figured it would make more sense to show a "Send download link" form instead of the Download button. Mobile visitors can download later when they get back to their Mac.
It looks something like this:
I wanted to ship fast, so I picked a super simple tech stack:
- UI: static hosted on Cloudflare Pages
- API: a simple Cloudflare Pages Function
- Email: Resend
Show me the code
Alright. I hope the code is self-explanatory enough 😅
UI Component
// DownloadLinkForm.jsx
import { useState } from 'react'
import { EnvelopeIcon } from '@heroicons/react/24/outline'
import { Button } from './Button'
import { TextField } from './Fields'
export function DownloadLinkForm() {
const [email, setEmail] = useState('')
const [sent, setSent] = useState(false)
const handleSendDownloadLink = async (e) => {
e.preventDefault()
try {
await fetch('/api/send-download-link', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
}),
})
setSent(true)
} catch (error) {
alert('An error occurred. Please try again.')
}
}
return (
<form method="post" onSubmit={handleSendDownloadLink}>
<div className="flex flex-wrap gap-x-4 gap-y-4 justify-center lg:justify-start block lg:hidden">
<div className="bg-gray-800 p-4 justify-center rounded-lg shadow-lg flex flex-col gap-4 w-80 border border-gray-400/10">
{sent ? (
<div className="text-white">
<p className="font-bold mb-2">✅ Email sent.</p>
<span className="text-white">
Check your inbox for the download link.
</span>
</div>
) : (
<>
<TextField
type="email"
name="email"
aria-label="Email address"
placeholder="Email address"
autoComplete="email"
required
autoFocus
className="min-w-0 shrink w-full"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Button
type="submit"
variant="solid"
color="cyan"
className="group px-12 bg-blue-600 w-full"
>
<EnvelopeIcon className="inline h-6 w-6 p-1 -mx-1 group-hover:animate-bounce" />
<span className="mx-2">Send download link</span>
</Button>
</>
)}
</div>
</div>
</form>
)
}
Pages Function
// /functions/api/send-download-link.ts
interface Env {
RESEND_API_KEY: string
}
type AppContext = EventContext<Env, any, any>
function makeResponse(code: number, data: string) {
return new Response(JSON.stringify({ code, data }), {
status: code,
headers: {
'content-type': 'application/json;charset=UTF-8',
},
})
}
interface RequestBody {
email: string
}
export async function onRequestPost(context: AppContext): Promise<Response> {
const { request } = context
if (!context.env.RESEND_API_KEY) {
return makeResponse(500, 'App Not Configured')
}
if (request.method !== 'POST') {
return makeResponse(405, 'Method Not Allowed')
}
const requestBody = (await request.json()) as RequestBody
const url = 'https://api.resend.com/emails'
const init = {
method: 'POST',
headers: {
Authorization: `Bearer ${context.env.RESEND_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'PDF Pals <[email protected]>',
to: requestBody.email,
subject: 'Your PDF Pals download link',
html: `<p>Hello. Your PDF Pals download link is ready:</p>
<p><a href="https://pdfpals.com/latest">https://pdfpals.com/latest</a>
<p>If you have troubles downloading the app, feel free to send us an email at [email protected]</p>
<p>Best,</p>
<p>Daniel<br/> Founder of PDF Pals</p>
`,
}),
}
const response = await fetch(url, init)
return response
}
If you are new here, PDF Pals is a native macOS app that allows you to chat with local PDFs instantly. Download now.