Skip to content

Integration guide · Laravel

A Laravel contact form that emails you — no Mailable required

A contact form in Laravel doesn't need a Mailable class, a queued job, or Mail server credentials. Drop a plain HTML form in a Blade view pointed at a PostTo endpoint and submissions arrive by email — no @csrf token needed, since the form posts to PostTo directly, not to your own app.

Prefer to keep the request server-side? A controller can forward the payload through PostTo's HMAC-signed API using Laravel's Http facade — the signing secret stays in .env, never in the browser.

Free plan, no credit card required.

Three steps, a few minutes

1

Create an endpoint

Sign up free, create an endpoint in the dashboard, and set your destination email. You'll get an endpoint URL right away — and a signing secret if you enable signed mode.

2

Pick your integration

Simplest: a plain form in a Blade view. More control: a controller action that signs the request server-side with the Http facade.

3

Ship it

No Mailable, no mail driver configuration, no queue worker to keep running for this. Submissions land in your inbox and dashboard.

The code

Replace YOUR_TOKEN with the endpoint URL from your dashboard.

resources/views/contact.blade.php — plain form
<form action="https://postto.dev/api/v1/send/YOUR_TOKEN" method="POST">
    <label for="name">Name</label>
    <input type="text" id="name" name="name" required>

    <label for="email">Email</label>
    <input type="email" id="email" name="email" required>

    <label for="message">Message</label>
    <textarea id="message" name="message" required></textarea>

    {{-- Honeypot: bots fill this in, humans never see it --}}
    <input type="text" name="_hp" tabindex="-1" autocomplete="off" style="display:none">

    {{-- Where to send the visitor after a successful submission --}}
    <input type="hidden" name="_next" value="{{ route('contact.thanks') }}">

    <button type="submit">Send</button>
</form>
app/Http/Controllers/ContactController.php — signed mode, secret stays server-side
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

public function store(Request $request)
{
    $payload = $request->validate([
        'name' => ['required', 'string'],
        'email' => ['required', 'email'],
        'message' => ['required', 'string'],
    ]);

    $ts = (string) now()->timestamp;
    $body = json_encode($payload);
    $signature = hash_hmac('sha256', "{$ts}.{$body}", config('services.postto.secret'));

    $response = Http::withHeaders([
        'Accept' => 'application/json',
        'X-PostTo-Timestamp' => $ts,
        'X-PostTo-Signature' => $signature,
    ])->withBody($body, 'application/json')
        ->post('https://postto.dev/api/v1/send/YOUR_TOKEN');

    return back()->with('status', $response->successful() ? 'sent' : 'failed');
}

Good to know

No CSRF token needed on the plain form

The form posts to postto.dev, not back to your own app, so Laravel's @csrf directive isn't relevant here — VerifyCsrfToken only checks requests hitting your own routes.

Keep the secret out of config that ships to the frontend

Signed mode needs the endpoint's secret key, so store it with config('services.postto.secret') backed by an .env value — never expose it in a Blade view or a Vite-bundled asset.

Spam protection is already wired in

The hidden _hp field is a honeypot — humans never see it, bots fill it in, and PostTo silently discards those submissions. Server-side baseline filtering (heuristics and optional AI classification) runs on every submission after that, so you don't need a CAPTCHA to start.

Frequently asked questions

Do I need a Mailable or a queued job for this?
No — for the plain form, PostTo handles delivery entirely; Laravel's Mail component and queue workers aren't involved. Only the signed-mode controller example touches your own app code, and even then it's a single Http facade call, not a Mailable.
Does the plain form work with Livewire pages?
Yes, but it doesn't need Livewire — it's a native HTML form, so embedding it in a Livewire component's Blade view works without any wire:submit binding.
When should I use signed mode instead of the plain form?
Use the plain form for a public contact page — the endpoint token plus baseline spam filtering is the right level of protection. Use signed mode when the request originates from your own backend and you want cryptographic proof it wasn't forged or replayed.
What does it cost?
The free plan includes 50 submissions per month with the full dashboard — no credit card required. Paid plans start at $9/month.

Add a form to your Laravel site today

Create an endpoint, paste the snippet, and see your first submission in the dashboard — all on the free plan.

Try PostTo free