4 · Email (SMTP)
Objective — wire transactional email and prove it actually sends — the hard part is finding where SMTP resolves at runtime, because the most common vendor family loads it from the DB and the panel’s warning banner lies about it.
Background
Section titled “Background”Transactional email is a MUST — password resets, invoices, and notifications all depend on it, and section 1 of page 3 warned you not to change the admin email until mail works. The hard part isn’t the SMTP fields; it’s knowing where the app actually reads them from — and on the most common CodeCanyon vendor family, the admin UI actively lies about that.
1. Find the real source of truth
Section titled “1. Find the real source of truth”Before touching any field, decide where SMTP config actually resolves at runtime. The brand survey (page 2) already flagged whether the vendor ships a CustomConfigProvider; confirm it now.
flowchart TD Q{"Does a CustomConfigProvider /<br/>SettingsProvider rewrite mail config<br/>at boot from a DB table?"} Q -->|Yes — Froiden family| DB["DB table is truth<br/>(email_settings).<br/>Configure the ADMIN PANEL.<br/>.env MAIL_* = fallback only"] Q -->|No admin Email tab at all| ENV["Configure shared/.env MAIL_*<br/>(see Phase 8 email infra)"] Q -->|Panel present, no provider| PANEL["Admin panel writes config<br/>directly — use it"]-
Grep for a provider that rewrites mail config at runtime.
Terminal window grep -rn "mail\.mailers\.smtp\|Config::set.*mail" app/Providers/ app/Http/Middleware/ 2>/dev/null | headfind app/ -name "*ConfigProvider*" -o -name "*SettingsProvider*" 2>/dev/null# Expected: a provider that calls Config::set('mail...'), or no match- ✅ If a provider calls
Config::set('mail.mailers.smtp.*', DB::table(...)), the database overrides.envand the admin panel is the source of truth; otherwise.envis.
- ✅ If a provider calls
The lesson generalizes beyond this one banner:
2. Configure SMTP in the admin panel
Section titled “2. Configure SMTP in the admin panel”Admin → Config → SMTP (or Settings → Email). This is a panel form a person fills and a panel button a person clicks — the test send and the inbox check are human-verified.
-
Fill the SMTP fields from your Phase 4 SMTP credentials + brand profile.
Field Value Mail From Name App name (brand profile) Mail From Email admin@[DOMAIN]SMTP Host e.g. smtp.hostinger.comSMTP Port 587(TLS) or465(SSL)Username / Password mailbox creds — paste the password via the clipboard bridge from page 3 §1 Encryption TLS(587) /SSL(465)- ✅ All fields are filled from real credentials; the password was pasted via the clipboard bridge.
-
Save, then click the panel’s own “Test SMTP” button — not
artisan tinker. Tinker sends through Laravel’s default mailer, which a CLI context may not have reconfigured via the provider yet.- ✅ “Test SMTP” succeeds and the dashboard “SMTP details are not correct” banner disappears — that’s your real success signal.
-
Trigger a password-reset on a test account and confirm the email arrives.
- ✅ A real password-reset email lands end-to-end in the inbox.
3. Set a sensible .env fallback (defence in depth)
Section titled “3. Set a sensible .env fallback (defence in depth)”Even when the DB path is truth, leave real MAIL_* values in shared/.env. If the email_settings row is corrupted or the provider query fails, Laravel falls back to .env. Real values = mail still works; garbage values = mail breaks silently.
-
Append the fallback idempotently (Python-free here, but
grep -qguards against duplicates; special-char passwords stay out of this block).Terminal window grep -q "^MAIL_HOST=" shared/.env || cat >> shared/.env <<'EOF'# SMTP fallback (.env defaults; runtime config overridden by CustomConfigProvider from DB)MAIL_MAILER=smtpMAIL_HOST=smtp.hostinger.comMAIL_PORT=465MAIL_ENCRYPTION=sslMAIL_FROM_ADDRESS=admin@[DOMAIN]MAIL_FROM_NAME="[APP_NAME]"EOF# Expected: the MAIL_* block is appended once (no duplicate on re-run)- ✅
shared/.envcarries realMAIL_*fallback values, appended only once.
- ✅
4. Review email templates & hygiene
Section titled “4. Review email templates & hygiene”-
Review the email templates (if the vendor exposes
Admin → Email Templates) — welcome, password-reset, invoice, and notification — setting the sender name, logo, and footer to match your brand (the email header logo you uploaded on page 3 lives here on some vendors).- ✅ Sender name, logo, and footer match the brand on every reviewed template.
-
Confirm no SMTP credentials are committed to git — they belong in
shared/.envon the server and your password manager only.- ✅ No SMTP secrets are tracked in git.
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 🤖 Source confirmed — where SMTP resolves at runtime (DB-via-provider vs
.env) is confirmed; the Froiden banner was verified against source, not trusted. - 👤 Panel SMTP saved — “Test SMTP” passes and the dashboard error banner is gone.
- 👤 Reset email received — a real password-reset email arrived end-to-end.
- 🤖
.envfallback set —shared/.envcarries realMAIL_*fallback values; no SMTP secrets in git. - 👤 Templates reviewed — sender, logo, footer reviewed if the vendor exposes them.