Add email verification to Lovable apps via a reference URL.
Paste this page's URL into your Lovable project description. The agent reads the spec below and scaffolds the verification call as a Supabase Edge Function — bearer token stays on the server, vrfymail's verdict shape lands intact.
Note: if you landed here troubleshooting Lovable's own account verification or setting up Lovable's email-sending feature, that's a different page — see Lovable's docs. This page is for developers using Lovable to build apps that need to verify their users' email addresses at signup.
The Lovable project description
Lovable's agent fetches URLs referenced in your project description and uses the content as context. The block below is the snippet to paste — references this URL, includes the spec inline as a fallback.
Add email verification to the signup form using vrfymail's API.
Reference: https://vrfymail.com/lovable-email-verification/
Behavior:
- On signup form submit, the server calls
POST https://vrfymail.com/v1/check
Headers: Authorization: Bearer ${process.env.MAIL_VERIFIER_KEY}
Content-Type: application/json
Body: { "email": "<email>", "strict": true }
- Response: { result, reason, reason_message, did_you_mean }
- did_you_mean non-null → inline suggestion + one-click apply
- undeliverable → block, show reason_message
- risky + role_account → soft yellow warning, allow submit
- deliverable | unknown → accept
Use Supabase Edge Function (or a Lovable backend function) so the bearer
token never reaches the client. No SDK install — fetch only. In Supabase dashboard → Edge Functions → Secrets, add MAIL_VERIFIER_KEY=vk_live_... Redeploy the function.
Submit the signup form in Lovable's preview. The verdict surfaces inline — typo suggestions, role-account warnings, blocks on undeliverable.
The Edge Function Lovable scaffolds
Lovable defaults to Supabase Edge Functions for server-side work. Here's the function that lands when the agent reads the spec above — the React form imports it and calls it on submit.
// supabase/functions/verify-email/index.ts
import { serve } from "https://deno.land/std/http/server.ts";
serve(async (req) => {
const { email } = await req.json();
const r = await fetch("https://vrfymail.com/v1/check", {
method: "POST",
headers: {
"Authorization": `Bearer ${Deno.env.get("MAIL_VERIFIER_KEY")}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email, strict: true }),
});
const verdict = await r.json();
if (verdict.did_you_mean) {
return new Response(
JSON.stringify({ ok: false, suggestion: verdict.did_you_mean }),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
if (verdict.result === "undeliverable") {
return new Response(
JSON.stringify({ ok: false, error: verdict.reason_message, code: verdict.reason }),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
if (verdict.result === "risky" && verdict.reason === "role_account") {
return new Response(
JSON.stringify({ ok: true, warn: verdict.reason_message }),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
// deliverable + unknown both pass.
return new Response(
JSON.stringify({ ok: true }),
{ status: 200, headers: { "content-type": "application/json" } }
);
}); On unknown, accept the signup.
unknown is what you get when the verification pipeline couldn't reach a verdict — DNS lookup failed, MX timed out. None of those are evidence the email is bad.
If you fail-closed on unknown, a real customer whose corporate DNS resolver hiccups for 800ms hits your form, gets rejected, bounces. The spec above encodes the right pattern: log it, accept the signup.
On vrfymail the cost-side argument vanishes too: unknown verdicts don't bill. refundUsage() releases the slot when the pipeline can't reach a verdict.
- deliverableAccept.
- unknownAccept. Log if you want a paper trail. Not billed.
- risky
role_account→ soft warning, allow submit. Other reasons → block. - undeliverableBlock. Show
reason_messageverbatim. - did_you_meanNon-null → suggest the correction inline. Works on any verdict.
One referenced URL, every Lovable session inherits the contract.
Lovable's agent reads project context on every turn. A referenced URL is durable — it doesn't get crowded out by your latest 50 chat messages, and it doesn't truncate the way an inline spec can on long projects.
Same pattern works in other AI builders — Bolt.new (project prompt), v0 (server-action prompt), Replit Agent (Secrets + agent prompt). See the AI builders hub for all ten.
Lovable + email verification, answered
- Does Lovable actually read URLs in the project description?
- Yes. Lovable's agent fetches URLs referenced in the project description or chat prompt and uses them as context. The page above is structured to read clean: explicit endpoint, response shape, handling rules. That's enough for Lovable to scaffold the verification call correctly without follow-up turns.
- Where do I add MAIL_VERIFIER_KEY in a Lovable project?
- Lovable projects use Supabase by default — open the Supabase dashboard for your project, go to Edge Functions → Secrets, add MAIL_VERIFIER_KEY=vk_live_... and redeploy the function. If you're using a Lovable backend that isn't Supabase, set the variable in whichever runtime is hosting your serverless functions.
- Lovable doesn't seem to generate edge functions by default — what then?
- Be explicit in the prompt: 'Add the email verification as a Supabase Edge Function (or a server-side function — never client-side).' Lovable scaffolds the function file and the React component that calls it. The key never reaches the browser. If you don't specify server-side, Lovable sometimes inlines the call into the React component, which leaks the bearer.
- Can I export a Lovable project and self-host?
- Yes. Click Export → Download or Connect to GitHub for ongoing sync. The vrfymail integration is portable — it's just a fetch in a server function. Re-set the env var in your destination runtime (Supabase, Vercel, Cloudflare, your own server) and the verification keeps working.
- What's the right way to handle verifyEmail latency in a Lovable React form?
- Call the function on submit, not on every keystroke. p50 latency is ~50ms; p99 is ~250ms. A signup form's submit-button latency budget is much higher than either. If you want inline feedback as the user types, debounce by 500ms on the email field's onBlur. Don't fire it on every keystroke — that bursts quota and produces flicker.
One reference URL. Every form, correct.
vrfymail's /v1/check returns a verdict in 50ms p50. Free tier: 5,000 verifies/month, no card. Paid plans start at $9/mo — see pricing.