Automate beta tester verification & onboarding with Trello, Gmail and QR codes
Pull contacts, verify each address with BillionVerify, and continue to Trello β only deliverable addresses get through.
Why verify before the send
Sending to invalid, risky, catch-all, or disposable addresses spikes your bounce rate and erodes sender reputation. A verification gate before the Trello step removes that risk automatically β only deliverable addresses continue, the rest are flagged.
The workflow
BillionVerify β verification sits right before the send.
Node by node
- 1WebhookSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 2Verifi EmailSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 3IFLogicΒ· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 4Generate Access CodeSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 5Respond ErrorSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 6Generate QR CodeSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 7QR Code URLSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 8HTML/CSS to ImageSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 9Verify Email (BillionVerify)VerifyΒ· billionverify
The BillionVerify node verifies the address β status (valid / invalid / risky / catch-all / role / disposable), is_deliverable, and a confidence score β before anything is sent.
- 10IF deliverableLogicΒ· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 11Send GmailSendΒ· n8n
Sends only to verified, deliverable addresses. Swap in your own provider node if you send elsewhere.
- 12Create a cardSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
- 13Respond SuccessSourceΒ· n8n
Provides or transforms the contact data flowing through the workflow.
Workflow JSON
Copy or download this workflow, then import it in n8n (Workflows β Import from File / Paste). Install the BillionVerify community node first, then add your API key credential.
{
"name": "Automate beta tester verification & onboarding with Trello, Gmail and QR codes + BillionVerify",
"nodes": [
{
"id": "eb6791dc-be3d-4929-a21a-e2602bd3e454",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
784,
848
],
"webhookId": "",
"parameters": {
"path": "beta-access",
"options": {},
"httpMethod": "POST",
"responseMode": "lastNode"
},
"typeVersion": 1
},
{
"id": "371245d6-c98f-4436-91c4-8767480c4147",
"name": "IF",
"type": "n8n-nodes-base.if",
"position": [
1280,
848
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.valid }}",
"value2": true
}
]
}
},
"typeVersion": 1
},
{
"id": "607b66f3-bb20-4c48-9523-def472f5529f",
"name": "Respond Error",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1744,
1072
],
"parameters": {
"options": {
"responseCode": 400
},
"respondWith": "json",
"responseBody": "={{ {\n \"status\": \"error\",\n \"message\": \"Invalid or disposable email address detected\",\n \"email\": $json.tester_email,\n \"reason\": $json.is_disposable ? \"Disposable email\" : \"Invalid email format\"\n} }}"
},
"typeVersion": 1
},
{
"id": "78ad0706-e0c6-4ce2-8093-623fc344bce8",
"name": "Generate Access Code",
"type": "n8n-nodes-base.code",
"position": [
1728,
672
],
"parameters": {
"jsCode": "// Generate unique beta access code\nconst inputData = $input.all();\n\nconst generateCode = () => {\n return \"BETA-\" + Math.random().toString(36).substring(2, 8).toUpperCase();\n};\n\nconst outputData = inputData.map(item => ({\n json: {\n ...item.json,\n access_code: generateCode(),\n timestamp: new Date().toISOString(),\n timestamp_readable: new Date().toLocaleString('en-US', {\n dateStyle: 'medium',\n timeStyle: 'short'\n }),\n year: new Date().getFullYear()\n }\n}));\n\nreturn outputData;"
},
"typeVersion": 2
},
{
"id": "61a0cac4-f03e-4cc1-8a87-d20fd67ffe98",
"name": "Generate QR Code",
"type": "n8n-nodes-base.httpRequest",
"position": [
1984,
672
],
"parameters": {
"url": "=https://api.qrserver.com/v1/create-qr-code/?data={{ $json.access_code }}&size=200x200&format=png",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.1
},
{
"id": "1ca7c61b-ac6c-4a77-b16d-c13e61eae6dd",
"name": "Send Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
2880,
672
],
"webhookId": "",
"parameters": {
"sendTo": "={{ $('Webhook').item.json.body.tester_email }}",
"message": "=<div style=\"font-family: 'Segoe UI', Arial, sans-serif; max-width: 600px; margin: 0 auto; background: #f8f9fa; padding: 20px;\">\n <div style=\"background: white; border-radius: 12px; padding: 40px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);\">\n \n <div style=\"text-align: center; margin-bottom: 30px;\">\n <h1 style=\"color: #0B84F3; margin: 0; font-size: 32px;\">π Welcome to Beta Testing!</h1>\n </div>\n \n <h2 style=\"color: #333; font-size: 20px;\">Hi {{ $('Webhook').item.json.body.tester_name }},</h2>\n \n <p style=\"color: #666; font-size: 16px; line-height: 1.6;\">\n Great news! Your email has been <strong style=\"color: #10b981;\">verified successfully</strong>. π\n </p>\n \n <p style=\"color: #666; font-size: 16px; line-height: 1.6;\">\n You're now officially part of the <strong>{{ $('Webhook').item.json.body.product_name }}</strong> Beta Testing Program. We're excited to have you on board!\n </p>\n \n <div style=\"background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%); padding: 25px; border-radius: 12px; margin: 30px 0; border-left: 4px solid #0B84F3;\">\n <h3 style=\"margin-top: 0; color: #333; font-size: 18px;\">π Your Beta Access Details</h3>\n \n <div style=\"margin: 15px 0;\">\n <p style=\"margin: 8px 0; color: #666;\">\n <strong>π Access Code:</strong> \n <code style=\"background: #0B84F3; color: white; padding: 8px 16px; border-radius: 6px; font-size: 18px; letter-spacing: 2px; font-weight: bold;\">{{ $('Generate Access Code').item.json.access_code }}</code>\n </p>\n </div>\n \n <p style=\"margin: 8px 0; color: #666;\"><strong>π¦ Product:</strong> {{ $('Webhook').item.json.body.product_name }}</p>\n <p style=\"margin: 8px 0; color: #666;\"><strong>π Signup Date:</strong> {{ $('Webhook').item.json.body.signup_date }}</p>\n <p style=\"margin: 8px 0; color: #666;\"><strong>β° Verified:</strong> {{ $('Generate Access Code').item.json.timestamp_readable }}</p>\n </div>\n \n <div style=\"background: #fff3cd; border: 1px solid #ffc107; border-radius: 8px; padding: 15px; margin: 20px 0;\">\n <p style=\"margin: 0; color: #856404; font-size: 14px;\">\n <strong>π Next Steps:</strong>\n </p>\n <ol style=\"color: #856404; font-size: 14px; margin: 10px 0; padding-left: 20px;\">\n <li>Save your access code securely</li>\n <li>Check your downloads for the official Beta Access Kit</li>\n <li>Use the QR code to activate your beta account</li>\n <li>Start testing and share your feedback!</li>\n </ol>\n </div>\n \n <p style=\"color: #666; font-size: 16px; line-height: 1.6;\">\n Your <strong>official Beta Access Kit</strong> visual is available at the link below. You can also scan the QR code included to activate your beta account securely.\n </p>\n \n <div style=\"text-align: center; margin: 30px 0;\">\n <a href=\"{{ $json.image_url }}\" style=\"display: inline-block; background: linear-gradient(135deg, #0B84F3 0%, #0066CC 100%); color: white; padding: 14px 32px; text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 16px; box-shadow: 0 4px 15px rgba(11, 132, 243, 0.3);\">π₯ View Your Access Kit</a>\n </div>\n \n <div style=\"background: #e3f2fd; border-radius: 8px; padding: 20px; margin: 25px 0;\">\n <p style=\"margin: 0; color: #1565c0; font-size: 14px;\">\n <strong>π‘ Need Help?</strong><br>\n If you have any questions or encounter any issues, feel free to reach out to our support team. We're here to help!\n </p>\n </div>\n \n <p style=\"color: #666; font-size: 16px; line-height: 1.6;\">\n Happy Testing! We can't wait to hear your feedback. π\n </p>\n \n <p style=\"color: #666; font-size: 16px; line-height: 1.6; margin-top: 30px;\">\n Best regards,<br>\n <strong>The {{ $('Webhook').item.json.body.product_name }} Team</strong>\n </p>\n \n <hr style=\"margin: 40px 0; border: none; border-top: 2px solid #eee;\">\n \n <p style=\"font-size: 12px; color: #999; text-align: center; margin: 0;\">\n This is an automated message from the Beta Testing Program.<br>\n Please do not reply directly to this email.<br>\n Β© {{ $('Generate Access Code').item.json.year }} All rights reserved.\n </p>\n \n </div>\n</div>",
"options": {},
"subject": "=π Welcome to {{ $('Webhook').item.json.body.product_name }} Beta Program"
},
"credentials": {
"gmailOAuth2": {
"id": "credential-id",
"name": "gmailOAuth2 Credential"
}
},
"typeVersion": 2.1
},
{
"id": "9bf7d30c-d2df-4077-b259-bd8e899e0ab9",
"name": "Respond Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3616,
672
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ {\n \"status\": \"success\",\n \"message\": \"Beta tester verified and access kit delivered successfully\",\n \"data\": {\n \"tester_name\": $json.tester_name,\n \"tester_email\": $json.tester_email,\n \"access_code\": $json.access_code,\n \"product_name\": $json.product_name,\n \"signup_date\": $json.signup_date,\n \"verification_timestamp\": $json.timestamp,\n \"access_kit_url\": $json.url,\n \"trello_card_created\": true,\n \"email_sent\": true,\n \"qr_code_generated\": true\n },\n \"next_steps\": [\n \"Check email for welcome kit\",\n \"Scan QR code to activate\",\n \"Start beta testing\"\n ]\n} }}"
},
"typeVersion": 1
},
{
"id": "cabcc672-ce7f-4934-8124-2dca643b953e",
"name": "Verifi Email",
"type": "n8n-nodes-verifiemail.verifiEmail",
"position": [
1040,
848
],
"parameters": {
"email": "={{ $json.body.tester_email }}"
},
"credentials": {
"verifiEmailApi": {
"id": "credential-id",
"name": "verifiEmailApi Credential"
}
},
"typeVersion": 1
},
{
"id": "3c0b3253-9ce7-43bd-af89-47c3e94c56c2",
"name": "HTML/CSS to Image",
"type": "n8n-nodes-htmlcsstoimage.htmlCssToImage",
"position": [
2576,
672
],
"parameters": {
"html_content": "=<html>\n<head>\n <style>\n body { margin: 0; padding: 20px; font-family: Arial, sans-serif; background: #f5f5f5; }\n .card { \n background: white; \n border: 3px solid #0B84F3; \n border-radius: 12px; \n padding: 40px; \n max-width: 600px; \n margin: 0 auto;\n box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n }\n h1 { color: #0B84F3; text-align: center; margin-bottom: 30px; }\n .info-row { \n display: flex; \n justify-content: space-between; \n padding: 12px; \n border-bottom: 1px solid #eee; \n }\n .label { font-weight: bold; color: #333; }\n .value { color: #666; }\n .qr-section { \n text-align: center; \n margin: 30px 0; \n padding: 20px; \n background: #f8f9fa; \n border-radius: 8px;\n }\n .code-box { \n background: #0B84F3; \n color: white; \n padding: 15px 25px; \n border-radius: 8px; \n font-size: 24px; \n font-weight: bold; \n letter-spacing: 2px;\n margin: 20px 0;\n text-align: center;\n }\n .footer { \n text-align: center; \n font-size: 12px; \n color: #999; \n margin-top: 30px; \n padding-top: 20px;\n border-top: 1px solid #eee;\n }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <h1>π Beta Tester Access Card</h1>\n \n <div class=\"info-row\">\n <span class=\"label\">Product:</span>\n <span class=\"value\">{{ $('Webhook').item.json.body.product_name }}</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"label\">Tester Name:</span>\n <span class=\"value\">{{ $('Webhook').item.json.body.tester_name }}</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"label\">Email:</span>\n <span class=\"value\">{{ $('Webhook').item.json.body.tester_email }}</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"label\">Signup Date:</span>\n <span class=\"value\">{{ $('Webhook').item.json.body.signup_date }}</span>\n </div>\n \n <div class=\"code-box\">\n {{ $json.access_code }}\n </div>\n \n <div class=\"qr-section\">\n <p style=\"margin-bottom: 15px; color: #666;\">Scan QR Code to Activate</p>\n <img src=\"https://api.qrserver.com/v1/create-qr-code/?data={{ $json.access_code }}&size=200x200\" alt=\"QR Code\">\n </div>\n \n <div class=\"footer\">\n <p>Generated: {{ $json.timestamp_readable }}</p>\n <p>β οΈ Keep this code confidential. Do not share publicly.</p>\n </div>\n </div>\n</body>\n</html>"
},
"credentials": {
"htmlcsstoimgApi": {
"id": "credential-id",
"name": "htmlcsstoimgApi Credential"
}
},
"typeVersion": 1
},
{
"id": "210532a5-f00c-4ee0-82e8-0098f63132cd",
"name": "Create a card",
"type": "n8n-nodes-base.trello",
"position": [
3136,
672
],
"parameters": {
"name": "={{ $('Webhook').item.json.body.tester_name }} β {{ $('Webhook').item.json.body.product_name }}",
"listId": "6908a49d052093d846300299",
"description": "=β
**Email Verified**\n\n**Tester Information:**\nπ€ **Name:** {{ $('Webhook').item.json.body.tester_name }}\nπ§ **Email:** {{ $('Webhook').item.json.body.tester_email }}\nπ **Access Code:** `{{ $('Generate Access Code').item.json.access_code }}`\nπ
**Signup Date:** {{ $('Webhook').item.json.body.signup_date }}\nβ° **Processed:** {{ $('Generate Access Code').item.json.timestamp_readable }}",
"additionalFields": {}
},
"credentials": {
"trelloApi": {
"id": "credential-id",
"name": "trelloApi Credential"
}
},
"typeVersion": 1
},
{
"id": "0285670a-7e85-42bd-be22-fd821e8af194",
"name": "QR Code URL",
"type": "n8n-nodes-base.set",
"position": [
2288,
672
],
"parameters": {
"fields": {
"values": [
{
"name": "qrcodeurl",
"stringValue": "=https://api.qrserver.com/v1/create-qr-code/?data={{ $json.access_code }}&size=200x200&format=png"
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "5a3d5242-14fd-486a-95c5-d8acd1e4b836",
"name": "Section: Input & Validation",
"type": "n8n-nodes-base.stickyNote",
"position": [
736,
576
],
"parameters": {
"color": 7,
"width": 712,
"height": 440,
"content": "\n## Anti-Fraud Email Gate\n\n**Why this matters** \nDisposable emails (10minutemail, temp-mail, etc.) = fake signups β wasted keys β polluted feedback.\n\n**What happens** \n- VerifiEmail checks: real inbox + not disposable \n- Valid β continue to access kit \n- Invalid β instant 400 error with reason\n\n**Success rate** \nCatches ~30% of junk signups in real betas\n"
},
"typeVersion": 1
},
{
"id": "657baf8c-7f95-4004-b042-8562e5baaac3",
"name": "Section: Error",
"type": "n8n-nodes-base.stickyNote",
"position": [
1664,
944
],
"parameters": {
"color": 7,
"width": 360,
"height": 264,
"content": "## Error Handling\n\nReturns 400 error with details when email validation fails (invalid format or disposable email detected)."
},
"typeVersion": 1
},
{
"id": "1c88dde8-7a44-4836-a77f-8fda92d8ad75",
"name": "Section: Kit Generation",
"type": "n8n-nodes-base.stickyNote",
"position": [
1664,
320
],
"parameters": {
"color": 7,
"width": 1072,
"height": 520,
"content": "## Instant Access Kit Creation\n\n**What gets created** \n- Unique code: `BETA-XXXXX` (6 chars, uppercase) \n- Scannable QR code (PNG) \n- Branded HTML access card with name, product, date \n- Direct image URL for email embed\n\n**Customization** \n- Edit colors in HTML/CSS to Image node (search `#0B84F3`) \n- Add your logo β replace placeholder in HTML \n- Change QR data (e.g., link to your dashboard)\n\n**QR currently contains** \nJust the access code β perfect for manual entry or future verification endpoint"
},
"typeVersion": 1
},
{
"id": "b1371181-fcb5-44b6-bdb4-17aeac225093",
"name": "Section: Notifications",
"type": "n8n-nodes-base.stickyNote",
"position": [
2784,
304
],
"parameters": {
"color": 7,
"width": 696,
"height": 524,
"content": "## Welcome Email + Team Tracking\n\n**Tester receives** \n- Beautiful HTML email with embedded access card \n- QR code + big access code \n- Next steps + excitement\n\n**Team gets (Trello)** \n- New card auto-created in your board \n- All tester details + signup time \n- Easy to assign feedback tasks\n\n**Why both?** \nDelight testers Β· Keep team perfectly synced\n\n**Bonus idea** \nAdd Google Drive node β auto-save all access cards!"
},
"typeVersion": 1
},
{
"id": "6f074679-0e85-476e-a359-c10b629222b8",
"name": "Section: Success",
"type": "n8n-nodes-base.stickyNote",
"position": [
3520,
544
],
"parameters": {
"color": 7,
"width": 360,
"height": 264,
"content": "## Success Response\n\nReturns 200 OK with complete tester data, access code, and confirmation flags for email sent and Trello card created."
},
"typeVersion": 1
},
{
"id": "a9ea5f43-47a5-4f34-a4dc-6ffdbd968950",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
560
],
"parameters": {
"width": 368,
"height": 432,
"content": "## 5-Minute Setup Guide\n\n1. **VerifiEmail** β Add your free API key (verifi.email) \n2. **Gmail** β Connect via OAuth2 (your account) \n3. **Trello** β Connect + pick a board/list for new testers \n4. **HTMLCSSToImage** β Add API key (htmlcsstoimg.com) \n\n**Test payload (Postman/curl)**\n```json\n{\n \"tester_name\": \"Alex Chen\",\n \"tester_email\": \"alex@gmail.com\",\n \"product_name\": \"SuperApp 2.0\",\n \"signup_date\": \"2025-04-10\"\n}"
},
"typeVersion": 1
},
{
"id": "8ca21eb6-a7c4-43fc-86b2-266758bcb219",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
336,
544
],
"parameters": {
"width": 352,
"height": 480,
"content": "## Beta Tester Onboarding & Access Kit Automation\n\n**What it does** \nAutomatically verifies beta signups β blocks disposable emails β instantly issues unique BETA-XXXXXX access codes + beautiful QR access card β emails welcome kit β logs tester in Trello β returns clean JSON.\n\n**Why you'll love it** \n- Stops 95% of fake beta signups instantly \n- Testers get professional welcome in <10 seconds \n- Zero manual work β fully webhook-ready \n- Perfect for SaaS, mobile apps, hardware betas\n\n**Use cases** \nEarly access programs Β· Closed betas Β· Hardware testing Β· VIP launches"
},
"typeVersion": 1
},
{
"parameters": {
"operation": "verify",
"email": "={{ $('Webhook').item.json.body.tester_email }}",
"additionalOptions": {}
},
"type": "n8n-nodes-billionverify.billionVerify",
"typeVersion": 1,
"position": [
2520,
672
],
"name": "Verify Email (BillionVerify)",
"credentials": {
"billionVerifyApi": {
"id": "",
"name": "BillionVerify account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "is-deliverable",
"leftValue": "={{ $json.is_deliverable }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
2700,
672
],
"name": "IF deliverable"
}
],
"connections": {
"IF": {
"main": [
[
{
"node": "Generate Access Code",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond Error",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Verifi Email",
"type": "main",
"index": 0
}
]
]
},
"Send Gmail": {
"main": [
[
{
"node": "Create a card",
"type": "main",
"index": 0
}
]
]
},
"QR Code URL": {
"main": [
[
{
"node": "HTML/CSS to Image",
"type": "main",
"index": 0
}
]
]
},
"Verifi Email": {
"main": [
[
{
"node": "IF",
"type": "main",
"index": 0
}
]
]
},
"Create a card": {
"main": [
[
{
"node": "Respond Success",
"type": "main",
"index": 0
}
]
]
},
"Generate QR Code": {
"main": [
[
{
"node": "QR Code URL",
"type": "main",
"index": 0
}
]
]
},
"HTML/CSS to Image": {
"main": [
[
{
"node": "Verify Email (BillionVerify)",
"type": "main",
"index": 0
}
]
]
},
"Generate Access Code": {
"main": [
[
{
"node": "Generate QR Code",
"type": "main",
"index": 0
}
]
]
},
"Verify Email (BillionVerify)": {
"main": [
[
{
"node": "IF deliverable",
"type": "main",
"index": 0
}
]
]
},
"IF deliverable": {
"main": [
[
{
"node": "Send Gmail",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}When to use this
- Cleaning a list before a Trello send or sync.
- Protecting Trello deliverability and sender reputation.
- Keeping bounce rates low so your sending is never throttled.
FAQ
Why verify before sending in Trello?
Verifying first keeps your bounce rate low, which protects your sender reputation and your results.
How do I import this workflow?
Download the JSON, then in n8n go to Workflows β Import from File (or paste it). Install the BillionVerify community node and add your API key credential.
What happens to risky or catch-all addresses?
They are routed to the false branch and excluded from the send. You decide whether to retry, review, or drop them.
Add verification to your workflow
Create a free account, grab your API key, and stop bounces before they happen.
Get started free