Skip to main content

Frameworks

Remix

Send email from a Remix route action with the top-level mail().


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

// app/routes/_index.tsx
import { Form } from '@remix-run/react'
import { useState } from 'react'
import { mail } from 'postboi'

export async function action({ request }: { request: Request }) {
	await mail({ body: request.formData() })
	return { ok: true }
}

export default function Index() {
	// Mirror the email into the hidden _reply_to field so replies reach the sender.
	const [email, setEmail] = useState('')

	return (
		<Form method="post" encType="multipart/form-data">
			<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/routes/_index.tsx
import { Form } from '@remix-run/react'
import { useState } from 'react'
import { mail } from 'postboi'

export async function action({ request }: { request: Request }) {
	await mail({ body: request.formData() })
	return { ok: true }
}

export default function Index() {
	// Mirror the email into the hidden _reply_to field so replies reach the sender.
	const [email, setEmail] = useState('')

	return (
		<Form method="post" encType="multipart/form-data">
			<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/remix-provider-postboi.