Occasion email verification with BillionVerify
Occasion is an e-commerce and booking platform designed for experience-based businesses such as tours, classes, and events. Integrating BillionVerify into your Occasion workflows means every customer email collected at checkout or registration is verified before confirmations are sent and contacts are saved.
Why verify before the send
Experience businesses rely on transactional emails β booking confirmations, reminders, and post-event follow-ups β reaching customers reliably. A single invalid or mistyped address at checkout means a missed confirmation and a frustrated customer. BillionVerify validates addresses at the point of entry so your communications always land.
Ready-to-use n8n workflow
Import this workflow into n8n β it verifies every address with BillionVerify before Occasion sends, so only deliverable contacts are emailed. Install the BillionVerify community node first, then add your API key. Adapted from this n8n template
{
"name": "Send personalized occasion wishes with AI, Google Sheets and Gmail + BillionVerify",
"nodes": [
{
"id": "0f023a71-85b7-4f0e-a02f-cbfaa9d89100",
"name": "Every Day at 8 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1120,
-64
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 24
}
]
}
},
"typeVersion": 1.2
},
{
"id": "419cacda-a902-427a-8b7c-769534544a21",
"name": "Date & Time",
"type": "n8n-nodes-base.dateTime",
"position": [
-928,
-64
],
"parameters": {
"options": {}
},
"typeVersion": 2
},
{
"id": "8f48ee04-443c-4d66-8e80-4d7f478bbef1",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-656,
-64
],
"parameters": {
"text": "=Today's date is: {{ $json.currentDate }}\n\nPlease check the Google Sheet resource for any occasions matching today's date (month and day only).\n\nOUTPUT FORMAT:\nWhen occasion is found, return ONLY valid format like this (no other text):\n[{\n \"hasOccasion\": true,\n \"email\": \"sarah@email.com\",\n \"subject\": \"Happy 30th Anniversary Sarah! πΉβ\",\n \"message\": \"Happy 30th Anniversary, my love!...\"\n}]\n\nWhen no occasion is found, return ONLY:\n[{\n \"hasOccasion\": false\n}]\n\nProceed now.",
"options": {
"systemMessage": "=You are my personal assistant specialized in relationship management and special occasion tracking.\n\nYOUR IDENTITY:\n- Thoughtful and detail-oriented\n- You help me maintain strong relationships by ensuring I never miss important dates\n- You have access to a Google Sheet containing all my friends' and family members' special occasions\n\nYOUR CAPABILITIES:\n- You can read and analyze dates from the Google Sheet resource attached\n- You understand different types of occasions: birthdays, anniversaries, graduations, engagements, etc.\n- You can calculate ages and anniversary years accurately\n- You generate personalized, heartfelt messages appropriate for different relationships\n\nYOUR RESPONSIBILITIES:\n1. Check if today matches any occasion in the sheet (compare month and day only, ignore year)\n2. If occasions are found today:\n - Extract all relevant details (Name, Email, Occasion_Type, Relationship, Personal_Note, Occasion_Date)\n - Calculate years passed (current year minus occasion year)\n - Use correct ordinal suffix (1st, 2nd, 3rd, 4th, 21st, 22nd, 23rd, etc.)\n - Generate warm, personalized messages that reflect the relationship type\n3. If no occasions are found today:\n - Simply respond: \"No occasions today.\"\n\nMESSAGE GUIDELINES:\n- Adapt tone based on relationship:\n * Spouse/Partner: Romantic, intimate, loving\n * Parents: Respectful, warm, appreciative\n * Siblings: Casual, playful, supportive\n * Friends: Friendly, fun, genuine\n * Professional contacts: Formal, respectful, professional\n- Reference the Personal_Note to add authentic, specific touches\n- Keep messages 3-5 sentences\n- Start birthday/anniversary messages with \"Happy [number][suffix] [occasion]!\"\n- Be genuine and heartfelt, never generic or robotic\n- Each message should feel unique and personal\n\nIMPORTANT RULES:\n- Match dates by MM-DD only (ignore the year in comparison)\n- Always calculate the correct age/years for context\n- Never send wishes if the date doesn't match\n- Process each person separately if multiple occasions exist today\n- Maintain privacy and handle personal information carefully\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2
},
{
"id": "1ea6f0a1-0017-4b76-9e93-00903bcdd0a0",
"name": "Get row(s) in sheet in Google Sheets",
"type": "n8n-nodes-base.googleSheetsTool",
"position": [
-496,
128
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/18i8WW1ytW7Zq255Djtj9Xg_uKIsAu9_Oqs452IkRiGQ/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "18i8WW1ytW7Zq255Djtj9Xg_uKIsAu9_Oqs452IkRiGQ",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/18i8WW1ytW7Zq255Djtj9Xg_uKIsAu9_Oqs452IkRiGQ/edit?usp=drivesdk",
"cachedResultName": "data"
},
"descriptionType": "manual",
"toolDescription": "Get row(s) in sheet in Google Sheets from the sheet named data."
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "credential-id",
"name": "googleSheetsOAuth2Api Credential"
}
},
"typeVersion": 4.7
},
{
"id": "94e4ccb3-9794-44f8-872b-e710197ffdec",
"name": "Send a message",
"type": "n8n-nodes-base.gmail",
"position": [
-96,
-64
],
"webhookId": "4ff5e570-eb90-4576-aee6-6f33f097ee86",
"parameters": {
"sendTo": "={{ $json.output.email }}",
"message": "={{ $json.output.message }}",
"options": {},
"subject": "={{ $json.output.subject }}"
},
"typeVersion": 2.1
},
{
"id": "778195ab-b64b-4c06-96e9-db0901d7c63b",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-656,
112
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "credential-id",
"name": "openAiApi Credential"
}
},
"typeVersion": 1.2
},
{
"id": "bdeccaf3-6199-4e8a-ab59-3a7d11000589",
"name": "Code in JavaScript",
"type": "n8n-nodes-base.code",
"position": [
-256,
-64
],
"parameters": {
"jsCode": "// Get the string returned by the AI agent\nlet raw = items[0].json.output;\n\n// Sometimes output may already be parsed, handle both cases\nlet parsed;\n\ntry {\n // Try to parse directly\n parsed = JSON.parse(raw);\n} catch (e) {\n // If output contains escaped JSON inside JSON, parse twice\n try {\n parsed = JSON.parse(JSON.parse(raw));\n } catch (e2) {\n throw new Error(\"AI output is not valid JSON array: \" + raw);\n }\n}\n\n// Ensure we always get an array\nif (!Array.isArray(parsed)) {\n parsed = [parsed];\n}\n\n// If no occasions found β [{ hasOccasion: false }]\nif (parsed.length === 1 && parsed[0].hasOccasion === false) {\n // Return zero items β nothing is sent\n return [];\n}\n\n// Convert each event into its own n8n item\nconst newItems = parsed.map(ev => ({\n json: {\n hasOccasion: ev.hasOccasion,\n email: ev.email,\n subject: ev.subject,\n message: ev.message\n }\n}));\n\nreturn newItems;\n"
},
"typeVersion": 2
},
{
"id": "186dc502-4b99-49cf-969f-63412a6938b4",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1776,
-176
],
"parameters": {
"width": 528,
"height": 480,
"content": "## Overview: Automated Occasion Wisher \n**How it works** \n- Runs daily to check if today matches any birthday, anniversary, or special occasion in your Google Sheet\n- AI Agent reads the sheet and returns list of users having special occasion to wish with details and personalized wishing message\n- If there is no one to wish, no email is sent. If there are multiple people to wish, multiple personalized emails are sent\n\n**Setup steps** \n\n- Connect your Google Sheet containing columns as: Name, Occasion_Date, Email,\tOccasion_Type, Relationship, Personal_Note\n- Insert the AI prompt ensuring strict JSON output (list format only)\n- Configure the Email node for sending the final message\n\n**Customization**\n\n- Edit AI prompt to change message tone, length, or emojis\n- Add support for multiple reminder styles (e.g., early notification)\n- Extend with logging, Slack alerts, or saving sent-email history\n"
},
"typeVersion": 1
},
{
"id": "1bd4a7de-1b07-4d63-bbb8-2da1c4881dca",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1152,
-176
],
"parameters": {
"color": 7,
"width": 352,
"height": 288,
"content": "## 1. Trigger Everyday and fetch current date "
},
"typeVersion": 1
},
{
"id": "cd9810d0-dac7-4280-8dda-8521d3edae99",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-720,
-176
],
"parameters": {
"color": 7,
"width": 352,
"height": 480,
"content": "## 2. AI Agent with Google Sheets resource"
},
"typeVersion": 1
},
{
"id": "bcd7d0f9-3e97-426e-8344-2c5ad7ac2552",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-304,
-176
],
"parameters": {
"color": 7,
"width": 352,
"height": 288,
"content": "## 3. Format output from AI Agent and send email if found any event "
},
"typeVersion": 1
},
{
"parameters": {
"operation": "verify",
"email": "={{ $json.output.email }}",
"additionalOptions": {}
},
"type": "n8n-nodes-billionverify.billionVerify",
"typeVersion": 1,
"position": [
-456,
-64
],
"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": [
-276,
-64
],
"name": "IF deliverable"
}
],
"connections": {
"AI Agent": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Date & Time": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Every Day at 8 AM": {
"main": [
[
{
"node": "Date & Time",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Verify Email (BillionVerify)",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet in Google Sheets": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Verify Email (BillionVerify)": {
"main": [
[
{
"node": "IF deliverable",
"type": "main",
"index": 0
}
]
]
},
"IF deliverable": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}Workflow templates with Occasion
Ready-to-use workflows that verify emails before Occasion sends.
How it works
- 1
Connect BillionVerify to your Occasion automations using the n8n community node, Integrately's 1-click setup, or the REST API.
- 2
Trigger a verification request each time a new booking or sign-up provides an email address.
- 3
BillionVerify validates syntax, checks domain MX records, and probes SMTP to confirm the mailbox exists and can receive mail.
- 4
Use the verification result to decide whether to proceed with booking confirmation, flag the address for review, or prompt the customer to re-enter their email.
- 5
Monitor overall list quality in the BillionVerify dashboard and use trend data to identify peak periods of fake sign-ups.
When to use this
Verify customer emails at booking checkout
Run each email address through BillionVerify the moment a customer completes a booking on Occasion. Catch typos and disposable addresses before sending the confirmation, reducing failed deliveries and customer confusion.
Clean your event attendee list before bulk sends
Before emailing event reminders or post-experience surveys to your full attendee list, validate every address with BillionVerify to eliminate hard bounces and protect your email deliverability score.
Filter out role and disposable addresses from newsletter sign-ups
When customers opt into your newsletter during checkout on Occasion, BillionVerify filters out role addresses and temporary inboxes so your subscriber list contains only genuinely interested contacts.
FAQ
How does email verification improve the booking experience?
Catching a typo at checkout lets you prompt the customer to correct it immediately, ensuring their confirmation arrives and reducing support tickets about missing booking emails.
Can BillionVerify handle high volumes during peak booking periods?
Yes. BillionVerify's API scales to handle large volumes with consistent response times, making it suitable for flash sales or popular event launches that drive sudden spikes in registrations.
What connection method should I use with Occasion?
Integrately's 1-click integration is the fastest way to connect Occasion with BillionVerify without writing code. For more complex logic, the n8n community node or REST API offer greater flexibility.
Does BillionVerify store the email addresses I verify?
BillionVerify processes addresses for verification purposes according to its privacy policy. No marketing or resale of your data occurs; results are returned to you and used solely to power your verification requests.
Verify emails in Occasion
Create a free account, grab your API key, and stop bounces before they happen.
Get started free