7.4 KiB
Mail setup — Google Workspace SMTP, sending as care@nearledaily.com
What this is for: the first-password invitation. Every back-office account on Fiesta is created with an empty password, and the link in this email is the only way to set one — the sign-in screen no longer offers a form, because a public one meant that knowing a merchant's email address was enough to claim their account.
So this is not newsletter plumbing. If the mail lands in spam, a business that was just onboarded cannot sign in, and the first anyone hears of it is a phone call. Step 3 is the one that decides that, and it is the one people skip.
The decisions
| why | ||
|---|---|---|
| Relay | Google Workspace SMTP | no server to run, no IP to warm, no port 25 exception to beg for. At a few dozen invitations a month that is the whole argument |
| Sender | care@nearledaily.com |
the link points at app.nearledaily.com; a password mail whose sender and destination are different domains is the shape of a phishing mail |
care@ not no-reply@ |
somebody replying "I never got this" is the most useful reply this system can receive, and it should reach a person | |
| Auth | an App Password, never the login password | it can be revoked on its own if it leaks |
This replaces an earlier plan to self-host Postal. Postal is the better answer at volume; it is the wrong answer for tens of emails a month, because the work is not the software — it is IP reputation, rDNS and blocklists.
Step 1 — Google Workspace on nearledaily.com
- Sign up at workspace.google.com with
nearledaily.com. Business Starter is enough. - Verify the domain with the TXT record Google gives you.
- Create
care@nearledaily.com. It is a real mailbox and somebody has to read it — merchant replies and bounce notices both land there, and a bounce is how you learn an invitation never arrived.
Step 2 — DNS on nearledaily.com
| Record | Name | Value |
|---|---|---|
| MX | nearledaily.com |
smtp.google.com (priority 1) |
| TXT (SPF) | nearledaily.com |
v=spf1 include:_spf.google.com ~all |
| TXT (DKIM) | google._domainkey |
the key from Step 3 |
| TXT (DMARC) | _dmarc |
v=DMARC1; p=none; rua=mailto:care@nearledaily.com |
- One SPF record only. If the domain already has one, merge
include:_spf.google.cominto it. Two SPF records is a permerror and fails every check. - Remove old MX records if the domain receives mail somewhere else today, or that mail keeps going to the old place.
- Keep DMARC at
p=nonefor a couple of weeks, read the reports, then move top=quarantine. Going straight top=rejectis how you find a misaligned sender by losing its mail.
Step 3 — DKIM (the step people skip)
Admin console → Apps → Google Workspace → Gmail → Authenticate email.
- Generate new record (2048-bit), add the TXT record it prints to DNS.
- Wait for DNS to propagate — minutes to hours.
- Come back and click Start authentication.
Until you click that last button the mail is unsigned, and unsigned mail carrying a password link goes to spam.
Step 4 — An App Password for Fiesta
- Sign in as
care@nearledaily.com→ Google Account → Security → turn on 2-Step Verification. - Security → App passwords → create one named
Fiesta. You get 16 characters. - That is what Fiesta uses. Never the account's real password.
No App passwords option? An admin has to allow it, or set up Admin console →
Gmail → Routing → SMTP relay service with "require SMTP authentication" and
"require TLS". In that case MAIL_HOST becomes smtp-relay.gmail.com.
Step 5 — Point Fiesta at it
Credentials go in .env.secrets, which is read first and is the only env
file git ignores. Never in .env — that one is tracked and shared.
MAIL_HOST=smtp.gmail.com
MAIL_USERNAME=care@nearledaily.com
MAIL_PASSWORD=<16-character app password>
Already set in .env:
MAIL_PORT=587
MAIL_FROM=care@nearledaily.com
MAIL_FROM_NAME=Nearle
MAIL_CONSOLE_URL=https://app.nearledaily.com
Google shows the App Password as four groups — abcd efgh ijkl mnop. Paste it
with or without the spaces; Fiesta strips them for Google SMTP hosts only, and
only when what remains is the sixteen alphanumerics an App Password actually is.
Another relay's password is never edited.
MAIL_CONSOLE_URL is the merchant console and never the platform one — a
merchant sets their password at app.nearledaily.com/set-password and nowhere
else.
Restart. The log says which state it is in:
mail: sending as care@nearledaily.com via smtp.gmail.com:587
mail: OFF — <reason naming the missing variable>
On a hosted deployment these belong in the platform's own environment
(Dokploy), not in a file in the repo. A .env committed to the repository is
overwritten at build time — that is how the nutrition service shipped switched
off.
What Fiesta does with them
utils/mail.go upgrades to TLS with STARTTLS before authenticating, and
refuses to send at all if a relay offers no encryption while credentials are
configured. Go's own smtp.PlainAuth would decline to hand over the password
anyway, so nothing leaks either way — but it reports that as the server refusing
the credentials, which sends somebody to check the password when the problem is
the connection. It also closes a downgrade, where an attacker strips STARTTLS
from the greeting.
Step 6 — Check the DNS
dig TXT nearledaily.com +short # SPF, with _spf.google.com
dig TXT google._domainkey.nearledaily.com +short # DKIM key
dig TXT _dmarc.nearledaily.com +short # DMARC
dig MX nearledaily.com +short # smtp.google.com
Google's Check MX tool at toolbox.googleapps.com does the same job.
Step 7 — Prove it end to end
Not "the config looks right" — watch one arrive.
- Send a test to a mail-tester.com address. Aim for 9/10 or better before a real merchant sees one.
- Onboard a test merchant with an address you can read.
- Confirm it is in the inbox, not spam. In Gmail, "Show original" should show SPF, DKIM and DMARC all PASS.
- Follow the link, set a password, sign in at
app.nearledaily.com. - Press Resend invite. It must refuse, naming the business: "… has already set a password — send them to the sign-in page instead." That refusal is what stops this becoming a password reset.
Worth knowing
- Limit: about 2,000 messages a day per user. Onboarding runs at a few dozen a month, so this is not a constraint.
- Bounces arrive as "Delivery failed" in the
care@inbox. Nothing in Fiesta watches for them, so somebody has to read that mailbox after onboarding. - Not for bulk. Google does not permit marketing sends through Workspace. If newsletters are ever wanted, that is a separate provider — not this mailbox.
- If the App Password leaks: revoke it in Google Account → Security, issue a
new one, update
.env.secrets. Nothing else has to change.
What the merchant receives
Plain text, deliberately. A password link arriving as an image-heavy HTML template is the shape of a phishing mail, and plain text renders identically everywhere. The body names the business, puts the link on its own line, and says it expires in seven days — because an invitation found three weeks later needs to explain itself rather than look broken.
The wording is inviteMessage in services/inviteService.go.