Email Verification in n8n: An Importable Signup Workflow
This n8n workflow turns a webhook into a small signup decision service. It receives an email address, makes one authenticated request to emailverifier.dev, maps the result, and answers the original webhook with allow, review, or block.
Signup Webhook -> Verify Email -> Map Decision -> Return Signup Decision
There is no database node in the workflow. Your application should create the account only after it receives allow.
Import the four-node workflow
Save the JSON below as verify-signup-email.json, open n8n, and choose Import from File from the workflow menu.
{
"name": "Verify signup email",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "verify-signup-email",
"responseMode": "responseNode",
"options": {}
},
"id": "9d883c5d-9093-4cb3-9ef7-7d15a31400b8",
"name": "Signup Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [0, 0],
"webhookId": "verify-signup-email"
},
{
"parameters": {
"method": "POST",
"url": "https://emailverifier.dev/api/v1/verify",
"sendHeaders": true,
"headerParameters": {
"parameters": [{
"name": "X-API-Key",
"value": "={{ $env.EMAILVERIFIER_API_KEY }}"
}]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ email: $('Signup Webhook').item.json.body.email }) }}",
"options": { "timeout": 4000 }
},
"id": "a4bb53a2-36fb-4852-95f9-6dcc0fb202fd",
"name": "Verify Email",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [240, 0]
},
{
"parameters": {
"jsCode": "const report = $input.first().json;\n\nconst statusCode = report.action === 'block' ? 422 : report.action === 'review' ? 202 : 200;\n\nconst message = report.action === 'block' ? (report.suggestion ? 'Check the spelling of your email address.' : 'Use a different email address.') : report.action === 'review' ? 'Confirm this address before receiving full access.' : 'Continue to account creation.';\n\nreturn [{ json: { statusCode, decision: report.action, message, signals: report.signals, suggestion: report.suggestion } }];"
},
"id": "f0460e17-0da7-474f-a42a-0bf5b0714a2b",
"name": "Map Decision",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [480, 0]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": { "responseCode": "={{ $json.statusCode }}" }
},
"id": "49fe148c-bf8f-48cb-8c16-c3cb37f227f5",
"name": "Return Signup Decision",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.4,
"position": [720, 0]
}
],
"connections": {
"Signup Webhook": {
"main": [[{"node":"Verify Email","type":"main","index":0}]]
},
"Verify Email": {
"main": [[{"node":"Map Decision","type":"main","index":0}]]
},
"Map Decision": {
"main": [[{"node":"Return Signup Decision","type":"main","index":0}]]
}
},
"pinData": {},
"settings": { "executionOrder": "v1" },
"active": false
}
The workflow uses n8n’s core Webhook, HTTP Request, Code, and Respond to Webhook nodes. Keeping the mapping in one Code node makes the imported artifact readable and avoids three nearly identical response branches.
Provide the API key without putting it in the export
Create an emailverifier.dev account and project, then copy its API key. Add it to the n8n process environment as EMAILVERIFIER_API_KEY and restart n8n.
export EMAILVERIFIER_API_KEY="your-project-key"
n8n start
The HTTP Request node reads $env.EMAILVERIFIER_API_KEY. The secret is not embedded in the workflow JSON or returned by the webhook. If your n8n deployment blocks node access to environment variables, replace the header expression with an n8n Header Auth credential named for this project.
Test the workflow before activating it
Open Signup Webhook, select Listen for test event, and copy its test URL. Submit:
curl -X POST "YOUR_N8N_TEST_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"email":"person@example.com"}'
One execution should show one item moving through all four nodes. The HTTP Request node sends one request with this body:
{"email":"person@example.com"}
The webhook response uses:
422 blockfor a confirmed failure or blocking signal.202 reviewfor an inconclusive result that should proceed through confirmation or restricted access.200 allowfor the normal account-creation path.
The upstream verification statuses are deliverable, risky, undeliverable, and unknown. The Code node maps the separate action field instead of inventing policy from the status string.
Handle node failures deliberately
The imported workflow stops if the HTTP Request node times out or receives an API error. During testing, verify that your caller handles a failed or timed-out webhook as a retryable dependency failure.
For a production workflow that must always answer, add a node-level error workflow that returns 503. Do not turn a timeout, invalid API key, exhausted credit balance, or rate limit into 422 block. The API result-handling guide separates HTTP failures from address decisions.
After the test execution passes, activate the workflow and use the production webhook URL from your signup service. Protect that URL with your normal application authentication or an unguessable internal route. The webhook is a backend integration point, not a public email-checking form.