Email to info@ becomes a lead
Email sent to info@alhudatravels.in becomes a lead, and the lead becomes an enquiry in the work inbox (WRK-017). This page is how it is installed, checked and switched off.
How it works
info@ (Google Group) ──► a member's Gmail ──► Apps Script, every 5 min
│ POST, x-intake-secret
▼
email-intake (edge function)
│
▼
email_intake_record() ──► Lead (source: email)
│ trigger (WRK-002)
▼
Work inbox → Sales enquiries pool
- The script runs as a member of the info@ group whose Gmail receives every message. It reads mail. It changes nothing in Gmail and sends nothing.
- info@ is a Google Group. The group must let people outside the company post (Groups admin → info@ → Settings → Who can post: Anyone on the web), or customers' emails bounce before anything can read them.
- When the sender's domain has a strict DMARC policy (Yahoo, Outlook, many
companies), Groups shows the email as coming from info@ itself and puts the
real address in
X-Original-Sender/Reply-To. The capture reads the real sender from there, so these are not skipped as staff mail. - The function takes a shared secret,
EMAIL_INTAKE_SECRET. Without it the function refuses every call. - The database records each email once, by its Message-ID. A reply in a known thread, or a second email from someone whose enquiry is still open (within 30 days), joins that lead instead of making a new one.
- It skips mail from our own domains (forwards from staff), automated senders
(no-reply, mailer-daemon), auto-replies and bulk mail. Each skip is recorded with
its reason in
InboundEmail. - It reads a phone number and the trip type (Umrah, Hajj, Ziyarat) from the text when they are there. Otherwise the phone is empty and the trip type shows "Not said". Staff fill them in.
Deliberately not done: it does not reply to the sender (WRK-010). It does not save attachments; open the email in Gmail for those. It does not create bookings. Staff convert the lead as usual. Newsletters sent to info@ still become leads, because Google Groups marks every message the same way. Close those as lost with the reason "not an enquiry".
Install (once)
Order matters: the function must exist before the script calls it.
-
Make the secret, in WSL. It never goes into chat, into a file in the repo or into the script's code:
-
Deploy the function:
npx supabase functions deploy email-intake(verify_jwt = falseis set insupabase/config.toml; the secret is the check). - Pick the account. Use a Google account that is a member of info@ with delivery set to Each email. A dedicated mailbox is best, so the capture does not depend on one person's account.
- Create the script in that account: script.google.com → New project → paste
scripts/google-apps-script/email-intake.gs. Then Project Settings → Script properties → addEMAIL_INTAKE_SECRETwith the value from step 1. - Run
installonce and allow the Gmail and external-request permissions. It creates the 5-minute trigger and does a first pass over the last 24 hours.
Check it is working
- Send a test email to info@ from a personal address (not @alhudatravels.in, which is skipped). Within 5 minutes it appears on Leads with source email, and in Work → Pool as an email enquiry.
- The script's Executions page shows each run and how many messages it sent.
- In SQL:
select outcome, "skipReason", count(*) from "InboundEmail" group by 1, 2;
When it fails
- The script run fails with 401: the two secrets differ. Set them again (step 1 and step 4).
- 503
not_configured:EMAIL_INTAKE_SECRETis not set on Supabase. - 207, or an error per message: the database refused a message. The script keeps its last-run time, so the next run sends the same messages again. The reason is in the function's logs.
- Nothing is lost while it is failing: the email is still in Gmail, and the next successful run picks it up. Runs overlap by 15 minutes, and duplicates are ignored.
Switch it off
Delete the trigger in the script (Triggers → delete), or unset the secret with
npx supabase secrets unset EMAIL_INTAKE_SECRET. The function then refuses every
call. Leads already created stay.