// ═══════════════════════════════════════════════════════════════ // PROSPECT TRACKER (ENGLISH FUNNEL) — Apps Script // Webhook + automatic emails to your prospects // // Full instructions: see the "Tracking & follow-up guide" page of the funnel. // // Quick summary: // 1. Fill in the CONFIGURATION section below with YOUR information // 2. Save (Ctrl+S) // 3. Run initSheets() once (creates the Prospects + Follow-ups tabs) // 4. Deploy: Deploy > New deployment > Web app // → Execute as: Me | Who has access: Anyone // 5. Copy the URL → paste it in the funnel setup page (optional link field) // 6. Test with testFollowUps(), then switch on the daily run with createDailyTrigger() // ═══════════════════════════════════════════════════════════════ // ══ 1. CONFIGURATION ════════════════════════════════════════════ // → Replace each value with your own var DISTRIBUTOR_NAME = 'YOUR FIRST NAME'; var DISTRIBUTOR_FULLNAME = 'YOUR FIRST AND LAST NAME'; var DISTRIBUTOR_EMAIL = 'you@email.com'; var DISTRIBUTOR_PHONE = '+1 (000) 000-0000'; // Your TEST email address (for example: yourname+test@gmail.com) // testFollowUps() only sends to this address — real prospects are not touched // Leave '' to switch test mode off var TEST_EMAIL = ''; // ══ 2. STRUCTURE ════════════════════════════════════════════════ var SHEET_PROSPECTS = 'Prospects'; var SHEET_NUDGES = 'Follow-ups'; // Prospects columns (1-based) var PC = { ts:1, nom:2, email:3, phone:4, vidNum:5, vidTitle:6, tracking:7, lien:8 }; // Follow-ups columns (1-based) var NC = { email:1, nom:2, lien:3, inscription:4, a1:5, a2:6, a3:7, a4:8, a5:9, b1:10, b2:11, b3:12, b4:13, c1:14, c2:15, c3:16, c4:17, d:18, achete:19, type:20 }; // Section names — must match the funnel exactly var SECTION_C_MAP = { "Activate the Entrepreneur Within": 'c1', "Discover a Product Worth Sharing": 'c2', "Plug Into a Proven System": 'c3', "Start Your Business": 'c4' }; // Series A delays — days since the previous event // A1: sent at sign-up (welcome) | A2: 2 days after A1 | A3: 4 days | A4: 7 days | A5: 14 days var A_DELAYS = [2, 2, 4, 7, 14]; var A_KEYS = ['a1','a2','a3','a4','a5']; // Series B delays — days since the previous event (EWS sequence only) // B1: 5 days after the last video | B2: 3 days | B3: 5 days | B4: 7 days var B_DELAYS = [5, 3, 5, 7]; var B_KEYS = ['b1','b2','b3','b4']; // ══ 3. WEBHOOK ══════════════════════════════════════════════════ function doPost(e) { try { var data = JSON.parse(e.postData.contents); var ss = SpreadsheetApp.getActiveSpreadsheet(); var ps = getOrCreateSheet(ss, SHEET_PROSPECTS, getProspectsHeaders()); // Older sheets: add the "Series" column title if it is missing if (!ps.getRange(1, 9).getValue()) ps.getRange(1, 9).setValue('Series').setFontWeight('bold'); // Write the row (phone written separately as plain text) var nextRow = ps.getLastRow() + 1; ps.getRange(nextRow, 1, 1, 9).setValues([[ new Date(), data.prospect_name || '', data.prospect_email || '', '', // phone written below data.video_num || '', data.video_title || '', data.tracking_info || '', data.lien || '', seriesLabel(data.funnel_type) ]]); // Phone as plain text — stops Google Sheets from reading +1 as a formula var phoneCell = ps.getRange(nextRow, PC.phone); phoneCell.setNumberFormat('@'); phoneCell.setValue(data.prospect_phone || ''); var firstname; // Series finished → "you watched it all" email if (data.video_num === 'custom_complete' && data.prospect_email) { firstname = (data.prospect_name || 'there').split(' ')[0]; var completion; if ((data.funnel_type || '') === 'emg') { completion = buildEmGCompletionEmail(firstname, data.lien || ''); } else if ((data.funnel_type || '') === 'water') { completion = buildCustomCompletionEmail(firstname, data.lien || '', data.video_title || 'your series'); } else { completion = buildGenericCompletionEmail(firstname, data.lien || ''); } sendEmail(data.prospect_email, completion.subject, completion.html); } // Sign-up → create the Follow-ups row + welcome email to the prospect if (!data.video_num && data.prospect_email) { var funnelType = (data.funnel_type || 'ews'); var ns = getOrCreateSheet(ss, SHEET_NUDGES, getNudgesHeaders()); var isNew = upsertNudgesRow(ns, data.prospect_email, data.prospect_name || '', data.lien || '', funnelType); // Welcome email — only the FIRST time this prospect signs up if (isNew) { firstname = (data.prospect_name || 'there').split(' ')[0]; if (funnelType === 'water') { // No welcome email — the presentation opens right after sign-up } else if (funnelType === 'custom') { var wGen = buildGenericWelcomeEmail(firstname, data.lien || ''); sendEmail(data.prospect_email, wGen.subject, wGen.html); } else if (funnelType === 'emg') { var wEmg = buildEmGWelcomeEmail(firstname, data.lien || ''); sendEmail(data.prospect_email, wEmg.subject, wEmg.html); } else { // Plain-text welcome for the EWS sequence GmailApp.sendEmail( data.prospect_email, 'Welcome to your training', 'Hi ' + firstname + ',\n\n' + 'Welcome to your training!\n\n' + 'The first lesson is short. If you haven\'t seen it yet, ' + 'take ten quiet minutes and watch it.\n\n' + 'If you have questions at any point, just reply to this email ' + 'or click "Message me" inside the training.\n\n' + 'In the meantime, enjoy what comes next!\n\n' + DISTRIBUTOR_FULLNAME.split(' ')[0] + '\n' + DISTRIBUTOR_PHONE + '\n' + DISTRIBUTOR_EMAIL, { name: DISTRIBUTOR_FULLNAME, replyTo: DISTRIBUTOR_EMAIL } ); } // Mark A1 (Welcome) as sent → no duplicate from processNudges() var nsRows = ns.getDataRange().getValues(); for (var ni = 1; ni < nsRows.length; ni++) { if ((nsRows[ni][NC.email - 1] + '') === data.prospect_email) { ns.getRange(ni + 1, NC.a1).setValue(new Date()); break; } } } } return ContentService .createTextOutput(JSON.stringify({ status: 'ok' })) .setMimeType(ContentService.MimeType.JSON); } catch(err) { return ContentService .createTextOutput(JSON.stringify({ status: 'error', msg: err.toString() })) .setMimeType(ContentService.MimeType.JSON); } } // ══ 4. TEST & PRODUCTION ════════════════════════════════════════ /** * TEST — Run by hand (▶ Run in Apps Script) * Only processes TEST_EMAIL — your real prospects are NOT affected */ function testFollowUps() { if (!TEST_EMAIL) { Logger.log('⚠️ Set TEST_EMAIL at the top of the script before testing.'); return; } Logger.log('🧪 Test mode — processing: ' + TEST_EMAIL); processNudges(TEST_EMAIL); } /** * PRODUCTION — Called by the automatic daily trigger * Only switch it on once testFollowUps() has been checked */ function sendFollowUpsAuto() { processNudges(null); } // ══ 5. MAIN LOGIC ═══════════════════════════════════════════════ function processNudges(filterEmail) { var ss = SpreadsheetApp.getActiveSpreadsheet(); var ps = ss.getSheetByName(SHEET_PROSPECTS); var ns = ss.getSheetByName(SHEET_NUDGES); if (!ps || !ns) { Logger.log('❌ Tabs are missing. Run initSheets() first.'); return; } var prospects = buildProspectMap(ps); var nudgesData = ns.getDataRange().getValues(); var today = new Date(); for (var i = 1; i < nudgesData.length; i++) { var row = nudgesData[i]; var email = row[NC.email - 1]; if (!email) continue; if (filterEmail && email !== filterEmail) continue; var nom = (row[NC.nom - 1] || '') + ''; var lien = (row[NC.lien - 1] || '') + ''; var inscDate = row[NC.inscription - 1] ? new Date(row[NC.inscription - 1]) : null; var firstname = nom.split(' ')[0] || nom || 'there'; if (!inscDate) { Logger.log('⚠️ No sign-up date for ' + email); continue; } var p = prospects[email] || {}; var prospectType = (row[NC.type - 1] || 'ews') + ''; // ── Type C: section finished (EWS sequence) ───────────────────────── var sectionsCompleted = p.sectionsCompleted || []; for (var s = 0; s < sectionsCompleted.length; s++) { var sName = sectionsCompleted[s]; var cKey = SECTION_C_MAP[sName]; if (!cKey) continue; var cColIdx = NC[cKey] - 1; if (row[cColIdx]) continue; // already sent var mailC = buildSectionEmail(firstname, lien, sName, cKey); sendEmail(email, mailC.subject, mailC.html); ns.getRange(i + 1, NC[cKey]).setValue(new Date()); row[cColIdx] = new Date(); Logger.log('✅ C(' + cKey + ') → ' + email); } // ── Type D: purchase (you type "yes" in the Purchased column) ─────── var bought = (row[NC.achete - 1] + '').toLowerCase().trim(); if ((bought === 'yes' || bought === 'oui') && !row[NC.d - 1]) { var mailD = buildPurchaseEmail(firstname); sendEmail(email, mailD.subject, mailD.html); ns.getRange(i + 1, NC.d).setValue(new Date()); Logger.log('✅ D → ' + email); continue; } if (bought === 'yes' || bought === 'oui') continue; // buyers get no more reminders // ── Type A: signed up but has not watched anything yet ────────────── if (!p.hasVideos) { for (var ai = 0; ai < A_KEYS.length; ai++) { var aKey = A_KEYS[ai]; var aColIdx = NC[aKey] - 1; if (row[aColIdx]) continue; // already sent var aRef = (ai === 0) ? inscDate : (row[NC[A_KEYS[ai - 1]] - 1] ? new Date(row[NC[A_KEYS[ai - 1]] - 1]) : null); if (!aRef) break; // previous one not sent yet if (daysDiff(aRef, today) >= A_DELAYS[ai]) { var mailA = (prospectType === 'water') ? buildCustomNudgeAEmail(ai + 1, firstname, lien) : (prospectType === 'emg') ? buildEmGNudgeAEmail(ai + 1, firstname, lien) : (prospectType === 'custom') ? buildGenericNudgeAEmail(ai + 1, firstname, lien) : buildNudgeAEmail(ai + 1, firstname, lien); sendEmail(email, mailA.subject, mailA.html); ns.getRange(i + 1, NC[aKey]).setValue(new Date()); Logger.log('✅ A' + (ai + 1) + ' (' + prospectType + ') → ' + email); } break; // only one Series A email per run } } // ── Type B: started the EWS sequence, then stopped ────────────────── else if (prospectType === 'ews' && p.hasVideos && !p.completedAll && p.lastVideoDate) { for (var bi = 0; bi < B_KEYS.length; bi++) { var bKey = B_KEYS[bi]; var bColIdx = NC[bKey] - 1; if (row[bColIdx]) continue; // already sent var bRef = (bi === 0) ? p.lastVideoDate : (row[NC[B_KEYS[bi - 1]] - 1] ? new Date(row[NC[B_KEYS[bi - 1]] - 1]) : null); if (!bRef) break; if (daysDiff(bRef, today) >= B_DELAYS[bi]) { var mailB = buildNudgeBEmail(bi + 1, firstname, lien); sendEmail(email, mailB.subject, mailB.html); ns.getRange(i + 1, NC[bKey]).setValue(new Date()); Logger.log('✅ B' + (bi + 1) + ' → ' + email); } break; // only one Series B email per run } } } Logger.log('🏁 Done.'); } // ══ 6. HELPERS ══════════════════════════════════════════════════ function buildProspectMap(ps) { var rows = ps.getDataRange().getValues(); var map = {}; for (var i = 1; i < rows.length; i++) { var row = rows[i]; var email = (row[PC.email - 1] || '') + ''; var vidNum = (row[PC.vidNum - 1] || '') + ''; var vidTitle = (row[PC.vidTitle - 1] || '') + ''; var ts = row[PC.ts - 1] ? new Date(row[PC.ts - 1]) : null; if (!email) continue; if (!map[email]) map[email] = { hasVideos: false, lastVideoDate: null, sectionsCompleted: [], completedAll: false }; if (vidNum === 'section') { if (map[email].sectionsCompleted.indexOf(vidTitle) < 0) map[email].sectionsCompleted.push(vidTitle); } else if (vidNum) { map[email].hasVideos = true; if (ts && (!map[email].lastVideoDate || ts > map[email].lastVideoDate)) map[email].lastVideoDate = ts; if (vidNum === 'custom_complete') map[email].completedAll = true; var parts = vidNum.split('/'); if (parts.length === 2 && parts[0] === parts[1]) map[email].completedAll = true; } } return map; } // Returns true when a NEW row was created, false when the prospect was already there function upsertNudgesRow(ns, email, nom, lien, funnelType) { var rows = ns.getDataRange().getValues(); for (var i = 1; i < rows.length; i++) { if ((rows[i][NC.email - 1] + '') === email) { if (!rows[i][NC.lien - 1] && lien) ns.getRange(i + 1, NC.lien).setValue(lien); return false; } } var newRow = new Array(20).fill(''); newRow[NC.email - 1] = email; newRow[NC.nom - 1] = nom; newRow[NC.lien - 1] = lien; newRow[NC.inscription - 1] = new Date(); newRow[NC.type - 1] = funnelType || 'ews'; ns.appendRow(newRow); return true; } function daysDiff(d1, d2) { return Math.floor((d2.getTime() - d1.getTime()) / 86400000); } function sendEmail(to, subject, html) { // One invalid address must not stop the emails to the other prospects try { GmailApp.sendEmail(String(to || '').trim(), subject, '', { htmlBody: html, name: DISTRIBUTOR_FULLNAME, replyTo: DISTRIBUTOR_EMAIL }); } catch (err) { Logger.log('Email not sent to ' + to + ' : ' + err); } } function getOrCreateSheet(ss, name, headers) { var sheet = ss.getSheetByName(name); if (!sheet) { sheet = ss.insertSheet(name); sheet.appendRow(headers); sheet.setFrozenRows(1); } return sheet; } // Which series the prospect opened — shown in the "Series" column function seriesLabel(type) { if (type === 'emg') return '🛡️ emGuarde'; if (type === 'ews') return '💧 EWS'; if (type === 'water') return '💧 Kangen Water'; if (type === 'custom') return '🎬 Other series'; return ''; } function getProspectsHeaders() { return ['Timestamp','Name','Email','Phone','Video #','Video title','Tracking info','Link','Series']; } function getNudgesHeaders() { return [ 'Email', 'Name', 'Link', 'Signed up', 'Welcome', // A1 — sent at sign-up 'Reminder 2', // A2 — 2 days after A1 'Reminder 3', // A3 — 4 days after A2 'Reminder 4', // A4 — 7 days after A3 'Reminder 5', // A5 — 14 days after A4 'Follow-up 1', // B1 — 5 days with no activity 'Follow-up 2', // B2 — 3 days after B1 'Follow-up 3', // B3 — 5 days after B2 'Follow-up 4', // B4 — 7 days after B3 'Section 1 ✅', // C1 — congratulations after section 1 'Section 2 ✅', // C2 — congratulations after section 2 'Section 3 ✅', // C3 — congratulations after section 3 'Section 4 ✅', // C4 — congratulations after section 4 'Purchase email', // D — date the purchase email was sent 'Purchased ✅', // type "yes" here when the prospect buys 'Type' // ews, emg, water or custom (any other video series) ]; } function buildSignature() { return '

' + 'Talk soon,

' + '' + DISTRIBUTOR_FULLNAME.split(' ')[0] + '
' + DISTRIBUTOR_PHONE + '
' + DISTRIBUTOR_EMAIL + '

'; } function wrapEmail(lines, ctaText, ctaUrl, title) { var headerTitle = title || 'Entrepreneur training'; var body = lines.join('

'); var cta = (ctaText && ctaUrl) ? '

' + ctaText + '

' : ''; return '' + '
' + '' + '' + '
' + headerTitle + '
' + '

' + body + '

' + cta + '
' + buildSignature() + '
' + '
'; } function whatsappButton() { var whatsappLink = 'https://wa.me/' + DISTRIBUTOR_PHONE.replace(/\D/g,''); return 'Message me on WhatsApp →'; } // ══ 7. EMAILS — SERIES A (EWS sequence, nothing watched yet) ════ function buildNudgeAEmail(num, firstname, lien) { var cta = lien ? 'Watch the videos →' : ''; var data = [ { // A1 subject: 'Your training is waiting for you!', lines: [ 'Hi ' + firstname + ',', 'Your training is waiting for you!', 'I know how it goes… everyday life takes over and emails get buried.', 'Did you get a chance to start watching the videos?', 'If not, here is the link again ↓', 'If you have any question at all, just reply to this email. I answer every message personally.', 'Thank you, and enjoy the training! :)' ] }, { // A2 subject: 'Start your training! :)', lines: [ 'Hi ' + firstname + ',', 'A few days ago you signed up for our free training.', 'I just want to make sure you still have the link handy.', 'It only takes about ten minutes to get started.', 'Your training is right here ↓', 'Feel free to reply to this email. I answer personally.', 'Thank you! :)' ] }, { // A3 subject: 'A quick exercise for you, ' + firstname, lines: [ 'Hi ' + firstname + ',', 'Did you manage to find a little time to start your training?', 'If not, here is a quick exercise: think back to what made you want to do it in the first place.', 'Then give it a real chance to help you reach that goal.', 'The next video is waiting for you here ↓', 'Thank you! :)' ] }, { // A4 subject: 'Is this training still for you, ' + firstname + '?', lines: [ 'Hi ' + firstname + ',', 'Quick question: are these videos still something you want to watch?', 'If yes, they are right here whenever you have a moment ↓', 'Or maybe it just isn\'t the right time? Do you want me to keep sending you these little nudges? Let me know.', 'It may also be that this training isn\'t for you after all, and that is completely OK.', 'Just tell me. I will understand.', 'Thank you! :)' ] }, { // A5 subject: 'One last note, ' + firstname, lines: [ 'Hi ' + firstname + ',', 'This is my last reminder, I promise. I don\'t want to be the person cluttering your inbox.', 'The videos stay available here if you ever want to come back to them ↓', 'And if there was a topic you were hoping this training would cover, I would truly like to know. Just reply to this email.', 'Thank you for the attention you gave our training, and I wish you the very best! :)' ] } ][num - 1]; return { subject: data.subject, html: wrapEmail(data.lines, cta, lien) }; } // ══ 8. EMAILS — SERIES B (EWS sequence, started then stopped) ═══ function buildNudgeBEmail(num, firstname, lien) { var cta = lien ? 'Pick up where I left off →' : ''; var data = [ { // B1 subject: 'Any questions, ' + firstname + '?', lines: [ 'Hi ' + firstname + ',', 'I just wanted to check in.', 'Have you had a chance to move forward in your training?', 'If you have questions about what you have seen so far — the product, the opportunity or simply how the system works — reply to this email. I read and answer every message personally.', 'If you want to pick up where you left off, your training is waiting ↓' ] }, { // B2 subject: 'What you are about to discover next...', lines: [ 'Hi ' + firstname + ',', 'I want to give you a quick preview of what is coming in the next step of your training.', 'You will see exactly how this system works and how other people have made it part of their lives without turning everything upside down.', 'I think you will be surprised by how doable it is.', 'Continue my training ↓' ] }, { // B3 subject: firstname + ', others started exactly where you are', lines: [ 'Hi ' + firstname + ',', 'I want to share something that matters to me.', 'Most of the people who succeeded with this system had the very same doubts at the start: not enough time, not sure it was for them, not sure they would understand it all.', 'What made the difference?', 'They simply kept going.', 'Your training is still waiting for you ↓' ] }, { // B4 subject: firstname + ', shall we keep going together?', lines: [ 'Hi ' + firstname + ',', 'I have an offer for you.', 'If you would like, I am available to answer all your questions, by phone or simply by message.', 'Sometimes a ten-minute conversation clears up what is hard to put in an email.', 'Just reply to this email, or pick your training back up where you left off ↓', 'And if it truly isn\'t the right time, tell me. I will respect your decision and stop following up. :)' ] } ][num - 1]; return { subject: data.subject, html: wrapEmail(data.lines, cta, lien) }; } // ══ 9. EMAILS — SERIES C (EWS section finished) ═════════════════ function buildSectionEmail(firstname, lien, sectionName, cKey) { var cta = lien ? 'Continue my training →' : ''; var configs = { c1: { subject: 'Well done ' + firstname + '! First step complete 🎉', lines: [ 'Hi ' + firstname + ',', 'Well done!', 'You just completed a first important step in your training.', 'You finished the section "Activate the Entrepreneur Within."', 'You are already starting to see things differently, and that is exactly what makes the difference over the long run.', 'The next step is waiting: you are about to discover the product that makes all of this possible.', 'Continue my training ↓' ] }, c2: { subject: 'Well done ' + firstname + '! Now you know the product 🎉', lines: [ 'Hi ' + firstname + ',', 'Well done!', 'You just finished the section "Discover a Product Worth Sharing."', 'You now have a clear picture of what makes this product so unique and why sharing it comes so naturally.', 'The next step shows you the complete system that will support you throughout your business. You will not have to do it all alone.', 'Continue my training ↓' ] }, c3: { subject: 'Excellent ' + firstname + '! Now you have the system 🎉', lines: [ 'Hi ' + firstname + ',', 'Excellent!', 'You just finished the section "Plug Into a Proven System."', 'You now understand how this system supports you, how the numbers work and how to build something solid.', 'Only one step left: Start Your Business.', 'Finish my training ↓' ] }, c4: { subject: 'Congratulations ' + firstname + '! You finished your training 🎉', lines: [ 'Hi ' + firstname + ',', 'Congratulations!', 'You just completed your entire training.', 'You now hold every key to get started: you understand the product, the system and what it really takes.', 'The natural next step is to talk it through together and see how to begin.', 'I will be glad to guide you personally.', 'Just reply to this email or book a call. No obligation and no pressure. 🙂' ] } }; var config = configs[cKey] || configs['c4']; return { subject: config.subject, html: wrapEmail(config.lines, cKey !== 'c4' ? cta : '', lien) }; } // ══ 10. EMAIL — SERIES D (purchase) ═════════════════════════════ function buildPurchaseEmail(firstname) { return { subject: 'Welcome to the family, ' + firstname + '! 🎉', html: wrapEmail([ 'Hi ' + firstname + ',', 'Congratulations!', 'Your order is on its way. You just made a great decision.', 'Welcome to the family! 🎉', 'This is only the beginning, and I will be right beside you at every step: setup, getting started, everyday use and every question you have.', 'Never hesitate to contact me directly.', 'Talk very soon! 🙂' ], '', '', 'Welcome!') }; } // ══ 11. EMAILS — KANGEN WATER PRESENTATION (type "water") ═══════ var DEMO_TITLE = 'Webinar: Say Goodbye to Toxic Water'; // Series A — nothing watched yet (Kangen Water presentation) function buildCustomNudgeAEmail(num, firstname, lien) { var cta = lien ? 'Watch the presentation →' : ''; var data = [ { // A1 subject: 'Your presentation is waiting for you!', lines: [ 'Hi ' + firstname + ',', 'Your presentation is waiting for you!', 'I know how it goes... everyday life takes over and emails get buried.', 'Did you get a chance to start watching it?', 'If not, here is the link again ↓', 'If you have any question at all, just reply to this email. I answer every message personally.', 'Thank you, and enjoy! 🙂' ] }, { // A2 subject: 'This water is full of surprises...', lines: [ 'Hi ' + firstname + ',', 'A few days ago you signed up to discover this remarkable water, which has been part of daily life for families around the world for decades.', 'I would really love for you to see it.', 'Here is the link again, so you always have it handy.', 'Your presentation is waiting here ↓', 'Feel free to reply to this email. I answer personally.', 'Thank you, and enjoy!' ] }, { // A3 subject: 'A quick question for you, ' + firstname, lines: [ 'Hi ' + firstname + ',', 'Did you manage to find a little time to watch the presentation?', 'What made you want to see it in the first place?', 'Was it to do something about plastic and the environment? To find a better alternative to bottled water? Because you want better water for yourself and your family? To save money? Or simply out of curiosity?', 'Whatever your reason, this presentation will answer your questions.', 'It is waiting for you right here ↓' ] }, { // A4 subject: 'Is this presentation still for you, ' + firstname + '?', lines: [ 'Hi ' + firstname + ',', 'If yes, here is the link again. I would hate for it to get lost.', 'I am very curious to hear what you think of it.', 'Since I discovered this water, it is all my family and I drink every day. We are not about to give it up!', 'It is waiting for you here ↓' ] }, { // A5 subject: 'One last note', lines: [ 'Hi ' + firstname + ',', 'This is my last reminder, I promise.', 'I don\'t want to be the person cluttering your inbox.', 'The presentation stays available if you ever want to see it ↓', 'And if you have a question, or anything you would like to share, please reach out by WhatsApp or email.', 'I would truly like to help if I can.', 'Thank you!' ] } ][num - 1]; return { subject: data.subject, html: wrapEmail(data.lines, cta, lien, DEMO_TITLE) }; } // Sent when the prospect reaches the end of the Kangen Water presentation function buildCustomCompletionEmail(firstname, lien, seriesName) { var cta = lien ? 'Watch the presentation again →' : ''; return { subject: 'You watched the presentation, ' + firstname + ' — a few words from me', html: wrapEmail([ 'Hi ' + firstname + ',', 'You took the time to watch the presentation all the way through, and that truly means a lot to me.', 'I discovered this water years ago — and ever since, it is all my family and I drink every day. It is not one product among many. It is a decision you make once, and enjoy every single day.', 'Do you have questions? Something you would like to dig into, or simply your thoughts after watching it all? I would be really happy to talk it through with you.', 'Just reply to this email — I read and answer every message personally.', whatsappButton(), 'Talk very soon, I hope!' ], cta, lien, DEMO_TITLE) }; } // ══ 12. EMAILS — emGuarde SERIES ════════════════════════════════ var EMG_TITLE = '🛡️ emGuarde Series — EMF'; // Welcome email for the emGuarde series function buildEmGWelcomeEmail(firstname, lien) { var cta = lien ? 'Watch my videos →' : ''; return { subject: 'Your emGuarde series is ready, ' + firstname + '!', html: wrapEmail([ 'Hi ' + firstname + ',', 'Welcome to your emGuarde series!', 'In a few short videos you will discover what electromagnetic fields (EMF) are, what the research shows, and how emGuarde can help you look after your living space and the people you love.', 'Watch them at your own pace, ideally at a quiet moment.', 'And if you have any question at all — before, during or after — just reply to this email. I read and answer every message personally.', 'Enjoy!' ], cta, lien, EMG_TITLE) }; } // Series A — nothing watched yet (emGuarde series) function buildEmGNudgeAEmail(num, firstname, lien) { var cta = lien ? 'Watch the videos →' : ''; var data = [ { // A1 subject: 'Your emGuarde series is waiting for you!', lines: [ 'Hi ' + firstname + ',', 'Your emGuarde series is waiting for you!', 'I know how it goes... everyday life takes over and emails get buried.', 'Did you get a chance to start watching the videos?', 'If not, here is the link again ↓', 'If you have any question at all, just reply to this email. I answer every message personally.', 'Thank you, and enjoy! 🙂' ] }, { // A2 subject: 'Did you know EMF is present even in your living room?', lines: [ 'Hi ' + firstname + ',', 'A few days ago you signed up for our video series on EMF.', 'Did you know the electromagnetic fields from our everyday devices — phone, Wi-Fi, router — are present in our living spaces around the clock?', 'These videos explain clearly what the research says about it, and what you can do for your family.', 'Your emGuarde series is waiting here ↓', 'Reply directly if you have questions. I answer personally.', 'Thank you, and enjoy!' ] }, { // A3 subject: 'A quick question for you, ' + firstname, lines: [ 'Hi ' + firstname + ',', 'Did you manage to find a little time to watch the videos?', 'What made you want to see this series in the first place?', 'Was it concern for your children? Questions about your own exposure to EMF? Or simply curiosity about what science says on the subject?', 'Whatever your reason, these videos answer your questions in a concrete way, with no jargon.', 'They are waiting for you right here ↓' ] }, { // A4 subject: 'Is this series still for you, ' + firstname + '?', lines: [ 'Hi ' + firstname + ',', 'If yes, here is the link again. I would hate for it to get lost.', 'EMF is a hard subject to grasp, because we cannot see it or feel it directly. But the research keeps getting more precise.', 'These videos are short and concrete, and they give clear answers. I think you will be glad you watched.', 'Your emGuarde series is available here ↓' ] }, { // A5 subject: 'One last note, ' + firstname, lines: [ 'Hi ' + firstname + ',', 'This is my last reminder, I promise.', 'I don\'t want to be the person cluttering your inbox.', 'The videos stay available if you ever want to see them ↓', 'And if you have a question, or anything you would like to share, reach out by WhatsApp or email. I would truly like to help if I can.', 'Thank you!' ] } ][num - 1]; return { subject: data.subject, html: wrapEmail(data.lines, cta, lien, EMG_TITLE) }; } // Sent when the prospect reaches the end of the emGuarde series function buildEmGCompletionEmail(firstname, lien) { var cta = lien ? 'Watch the videos again →' : ''; return { subject: 'You watched the emGuarde series, ' + firstname + ' — a few words from me', html: wrapEmail([ 'Hi ' + firstname + ',', 'You took the time to watch the whole emGuarde series, and that truly means a lot to me.', 'EMF is a subject close to my heart. Since I discovered emGuarde, I can no longer imagine my living space without it.', 'Do you have questions? Something you would like to dig into, or simply your thoughts after watching it all? I would be really happy to talk it through with you.', 'Just reply to this email — I read and answer every message personally.', whatsappButton(), 'Talk very soon, I hope!' ], cta, lien, EMG_TITLE) }; } // ══ 13. EMAILS — ANY OTHER VIDEO SERIES (type "custom") ═════════ // Neutral wording: works for whatever videos you put in a series. var GENERIC_TITLE = 'Your videos'; function buildGenericWelcomeEmail(firstname, lien) { var cta = lien ? 'Watch my videos →' : ''; return { subject: 'Your videos are ready, ' + firstname + '!', html: wrapEmail([ 'Hi ' + firstname + ',', 'Welcome! Your videos are ready and waiting for you.', 'Watch them at your own pace, ideally at a quiet moment.', 'Keep this email: the button below takes you straight back to them any time.', 'And if you have any question at all — before, during or after — just reply to this email. I read and answer every message personally.', 'Enjoy!' ], cta, lien, GENERIC_TITLE) }; } function buildGenericNudgeAEmail(num, firstname, lien) { var cta = lien ? 'Watch the videos →' : ''; var data = [ { // A1 subject: 'Your videos are waiting for you!', lines: [ 'Hi ' + firstname + ',', 'Your videos are waiting for you!', 'I know how it goes... everyday life takes over and emails get buried.', 'Did you get a chance to start watching?', 'If not, here is the link again ↓', 'If you have any question at all, just reply to this email. I answer every message personally.', 'Thank you, and enjoy! 🙂' ] }, { // A2 subject: 'Ten minutes is all it takes to start', lines: [ 'Hi ' + firstname + ',', 'A few days ago you signed up to watch these videos.', 'I just want to make sure you still have the link handy.', 'It only takes about ten minutes to get started.', 'Your videos are right here ↓', 'Feel free to reply to this email. I answer personally.', 'Thank you!' ] }, { // A3 subject: 'A quick question for you, ' + firstname, lines: [ 'Hi ' + firstname + ',', 'Did you manage to find a little time to watch the videos?', 'Think back to what made you want to see them in the first place.', 'Then give them a real chance to answer your questions.', 'They are waiting for you right here ↓' ] }, { // A4 subject: 'Are these videos still for you, ' + firstname + '?', lines: [ 'Hi ' + firstname + ',', 'If yes, here is the link again. I would hate for it to get lost.', 'And if it just isn\'t the right time, or it isn\'t for you after all, that is completely OK. Just tell me.', 'I am very curious to hear what you think once you have watched.', 'Your videos are available here ↓' ] }, { // A5 subject: 'One last note, ' + firstname, lines: [ 'Hi ' + firstname + ',', 'This is my last reminder, I promise.', 'I don\'t want to be the person cluttering your inbox.', 'The videos stay available if you ever want to see them ↓', 'And if you have a question, or anything you would like to share, reach out by WhatsApp or email. I would truly like to help if I can.', 'Thank you!' ] } ][num - 1]; return { subject: data.subject, html: wrapEmail(data.lines, cta, lien, GENERIC_TITLE) }; } function buildGenericCompletionEmail(firstname, lien) { var cta = lien ? 'Watch the videos again →' : ''; return { subject: 'You watched it all, ' + firstname + ' — a few words from me', html: wrapEmail([ 'Hi ' + firstname + ',', 'You took the time to watch every video all the way through, and that truly means a lot to me.', 'Do you have questions? Something you would like to dig into, or simply your thoughts after watching it all? I would be really happy to talk it through with you.', 'Just reply to this email — I read and answer every message personally.', whatsappButton(), 'Talk very soon, I hope!' ], cta, lien, GENERIC_TITLE) }; } // ══ 14. UTILITIES ═══════════════════════════════════════════════ /** * initSheets() — Run ONCE to create the Prospects + Follow-ups tabs */ function initSheets() { var ss = SpreadsheetApp.getActiveSpreadsheet(); getOrCreateSheet(ss, SHEET_PROSPECTS, getProspectsHeaders()); getOrCreateSheet(ss, SHEET_NUDGES, getNudgesHeaders()); if (DISTRIBUTOR_EMAIL === 'you@email.com') { Logger.log('⚠️ Tabs created — but the CONFIGURATION section at the top still has the example values. Replace them with your own before deploying.'); } else { Logger.log('✅ Tabs created.'); } } /** * createDailyTrigger() — Run ONCE to switch on the automatic daily send at 9 AM * DO NOT run it before testFollowUps() has been checked! */ function createDailyTrigger() { var triggers = ScriptApp.getProjectTriggers(); for (var i = 0; i < triggers.length; i++) { if (triggers[i].getHandlerFunction() === 'sendFollowUpsAuto') ScriptApp.deleteTrigger(triggers[i]); } ScriptApp.newTrigger('sendFollowUpsAuto').timeBased().everyDays(1).atHour(9).create(); Logger.log('✅ Trigger on — sendFollowUpsAuto will run every day at 9 AM.'); }