Integrieren Sie ein Anmeldeformular in Next.js mit einer BFF-Route: Der Browser sendet an Ihre App; Ihre Route ruft Mailoo mit serverseitig gespeicherten Zugangsdaten auf. Verwenden Sie bevorzugt @mailoo/forms. Für den API-Vertrag siehe website-forms{.interpreted-text role="doc"}.
Voraussetzungen
- Ein Mailoo-Projekt mit einer Form-Integration (
FORM) - Ein API-Schlüssel mit
webhook.form-submission(oder FULL)
Umgebung (nur serverseitig)
@mailoo/forms verwendet standardmäßig das Umgebungsvariablen-Präfix MAILOO_CONTACT_FORM_INTEGRATION für FORM-Integrationen. Der Name ist historisch bedingt: Es handelt sich nicht um die CONTACT_FORM- (Feedback-)Integration. Feedback verwendet MAILOO_FEEDBACK_INTEGRATION -- siehe feedback-form-nextjs-example{.interpreted-text role="doc"}.
Fügen Sie Folgendes zu .env.local (oder Ihren Host-Secrets) hinzu:
MAILOO_CONTACT_FORM_INTEGRATION_API=https://api.mailoo.app
MAILOO_CONTACT_FORM_INTEGRATION_API_KEY=your-api-key-here
MAILOO_CONTACT_FORM_INTEGRATION_PROJECT_UID=your-project-uid-here
MAILOO_CONTACT_FORM_INTEGRATION_ID=your-form-integration-id-here
Alle vier sind für das Standardpräfix erforderlich. Verwenden Sie kein NEXT_PUBLIC_* für API-URL oder Schlüssel. Für eine zweite FORM-Integration übergeben Sie ein eigenes prefix (oder getConfig) an die Routenfabrik.
BFF-Routenhandler
// app/api/v1/webhooks/forms/submit/route.ts
import { createFormSubmitHandler } from '@mailoo/forms/routes'
export const POST = createFormSubmitHandler()
Client-Formular
Senden Sie an Ihr BFF. Body-Felder für FORM: email (erforderlich), optionale Felder name, subject, content, source, metadata. Verwenden Sie content (nicht message), wenn Sie einen eigenen Posteingangstext wünschen.
Mit dem Paket-Hook:
'use client'
import { useState } from 'react'
import { useMailooFormSubmit } from '@mailoo/forms/hooks'
export function NewsletterForm() {
const { submit, pending } = useMailooFormSubmit({
endpoint: '/api/v1/webhooks/forms/submit',
})
const [statusMessage, setStatusMessage] = useState('')
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
setStatusMessage('')
const fd = new FormData(e.currentTarget)
const result = await submit({
email: String(fd.get('email') || '').trim(),
name: String(fd.get('name') || '').trim() || undefined,
source: typeof window !== 'undefined' ? window.location.href : '',
})
if (!result.ok) {
setStatusMessage(result.message)
return
}
const data = result.data as { message?: string }
setStatusMessage(
typeof data.message === 'string' ? data.message : 'Subscribed'
)
}
return (
<form onSubmit={onSubmit}>
<input name="name" placeholder="Your name (optional)" disabled={pending} />
<input name="email" type="email" required disabled={pending} />
<button type="submit" disabled={pending}>
{pending ? 'Subscribing…' : 'Subscribe'}
</button>
{statusMessage ? <p>{statusMessage}</p> : null}
</form>
)
}
Alternativ können Sie fetch direkt mit derselben JSON-Struktur aufrufen.
Lifecycle-Ereignisse
Anonyme Newsletter-Anmeldung ist getrennt von der Registrierung eines identifizierten Benutzers. Nach dem Anlegen des Benutzers in Ihrer App senden Sie vom Server:
import { ingestMailooLifecycleEvent } from '@mailoo/forms/server'
import { MAILOO_LIFECYCLE_EVENTS } from '@mailoo/forms/events'
await ingestMailooLifecycleEvent({
eventName: MAILOO_LIFECYCLE_EVENTS.USER_REGISTERED,
idempotencyKey: `reg:${user.id}`,
externalUserId: user.id,
email: user.email,
marketingConsent: { granted: true, source: 'signup' },
})
App-Benutzer-ID als externalUserId übergeben (nicht Mailoo contactId). Browser → BFF: useMailooLifecycleEvent({ getHeaders }) für Host-Authorization. Bulk-Admin-Status: useMailooLifecycleStatus → ?externalUserIds=. Retry: POST .../events/{eventId}/retry via useMailooLifecycleRetry.
Standard-Umgebungspräfix: MAILOO_LIFECYCLE_*. Vollständiger Vertrag: lifecycle-events{.interpreted-text role="doc"}.
Verwandte Seiten
website-forms{.interpreted-text role="doc"} --- Endpunkt und Abonnenten-Verhaltenlifecycle-events{.interpreted-text role="doc"} ---user.registered/user.activatedfeedback-form-nextjs-example{.interpreted-text role="doc"} --- CONTACT_FORM / Feedbacknextjs-packages{.interpreted-text role="doc"} --- Paketübersicht