Skip to main content

Frameworks

Next.js

Send email from a Next.js Server Action with the top-level mail().


Postboi is framework-agnostic — read the request’s FormData in a Server Action and hand it straight to mail(). Postboi extracts the special fields and renders the rest into a tidy HTML table.

// app/actions.ts
'use server'
import { mail } from 'postboi'

export async function submit(_prev: unknown, body: FormData) {
	await mail({ body })
	return { ok: true }
}
// app/actions.ts
'use server'
import { mail } from 'postboi'

export async function submit(_prev: unknown, body: FormData) {
	await mail({ body })
	return { ok: true }
}

Point a client-component form at it. Include hidden _subject and _reply_to fields, and mirror the visitor’s email into _reply_to (with useState) so replying reaches the sender:

// app/page.tsx
'use client'
import { useActionState, useState } from 'react'
import { submit } from './actions'

export default function Page() {
	const [email, setEmail] = useState('')
	const [state, action] = useActionState(submit, null)

	return (
		<form action={action}>
			<input type="hidden" name="_subject" value="Contact Form" />
			<input type="hidden" name="_reply_to" value={email} />
			<input name="contact→name" placeholder="Name" required />
			<input
				name="contact→email"
				type="email"
				value={email}
				onChange={(e) => setEmail(e.target.value)}
				required
			/>
			<textarea name="details→message" placeholder="Message" />
			<button type="submit">Send</button>
		</form>
	)
}
// app/page.tsx
'use client'
import { useActionState, useState } from 'react'
import { submit } from './actions'

export default function Page() {
	const [email, setEmail] = useState('')
	const [state, action] = useActionState(submit, null)

	return (
		<form action={action}>
			<input type="hidden" name="_subject" value="Contact Form" />
			<input type="hidden" name="_reply_to" value={email} />
			<input name="contact→name" placeholder="Name" required />
			<input
				name="contact→email"
				type="email"
				value={email}
				onChange={(e) => setEmail(e.target.value)}
				required
			/>
			<textarea name="details→message" placeholder="Message" />
			<button type="submit">Send</button>
		</form>
	)
}

Field names use the fieldset→field syntax. The provider and default recipient come from postboi.config.ts — a POSTBOI_TOKEN routes to Postboi Cloud, or pick any provider.

Runnable example: examples/nextjs-provider-postboi.