10 days on the invisible: building an email system that supports production
10 days. 30 commits. Zero visible new features. While TAMSIV users were expecting a new button, a new color, or a new voice function, I spent each day rewriting something no one will ever see: how the app talks to people via email. And I realized that the invisible might account for 80% of what makes a product stick.
Key Takeaways
- A complete transactional email system: verification reminder, D+7 feedback loop, preferences, clean unsubscribe, per-user history.
- A Resend webhook that listens to 6 event types (delivered, opened, clicked, bounced, complained, delivery_delayed) to aggregate real-time metrics.
- An anti-impersonation RGPD flow: a user can report a welcome email they never requested, and the registration is immediately deleted.
- A daily cron that sends a unique reminder to unverified accounts after 3 days, i18n 6 languages.
- Two parallel mobile hotfixes (v1.07 + v1.08): gesture-handler audit, feed UI redesign, stable modals, 8 bugs fixed.
Why build an entire email system when Supabase Auth already sends verification emails?
That's a legitimate question. Supabase, in its default configuration, already sends a verification email upon signup. Many products stop there and add nothing else. That's enough to validate an email, but not to build a relationship with the user.
In production since April 4th, I found myself with dozens of accounts created but not verified. No follow-up. No D+7 feedback to know if the app was useful to them. No clean way for someone to say "this email wasn't for me." And most importantly, no admin-side visibility into what was sent, delivered, bounced, or marked as spam.
A custom transactional emailing system is exactly what separates a "technically functional" product from a product that looks serious. Big apps hide it behind their polish. Small apps neglect it and lose users without understanding why.
The daily cron that sends one, and ONLY ONE, reminder
The first brick laid is a daily cron that runs at a fixed time on Vercel. It queries the database, selects accounts created exactly 3 days ago and not yet verified, and triggers a unique reminder per user.
[PERSONAL EXPERIENCE] The "one reminder only" rule is intentional. I've received more abusive follow-up emails than I can count. Three reminders in 48 hours, five in a week, ten in a month. That's the best way to make people unsubscribe before they've even tried the product.
The cron writes to a dedicated table to track who received what and when. If a user has already been reminded, they are skipped. If the Resend send fails, the error is logged, but the cron does not automatically retry: I prefer visibility into failures over silent saturation.
The D+7 feedback loop: 4 buttons, 4 truths
[UNIQUE INSIGHT] Seven days after registration, each new user receives an email with 4 clickable buttons: I love it, I hate it, I have a suggestion, I found a bug. Each button points to a dedicated page that records the response and offers a free comment area.
Why this specific form? Because a Google Play rating is filtered by whoever has the most energy to leave it. An email with 4 buttons captures the silent truth. The truth of people who will never go to the store to write a comment, but who with one click can say "I didn't like it."
Technically, each button carries a signed token related to the user and the feedback type. The GET route on the website validates the token, records the response with the user_id and type, and displays the corresponding page with a free-form. No additional authentication to leave feedback: this is intentional. Friction kills feedback.
The anti-impersonation flow: RGPD without drama
Concrete case: someone creates a TAMSIV account with the email alice@exemple.fr. But Alice didn't ask for anything. She receives a welcome email for an account she never created. What does she do?
Without this flow, she puts the email in spam or reports the sender. In both cases, it's a loss: a loss for me in terms of sending reputation, a loss for her who has no clean way to close the matter, a loss for the person who made the typo and will never receive communication at the correct address again.
In the new version, each welcome email contains a "I didn't create this account" link. Click, dedicated page, confirmation. The registration is immediately deleted from the database, a log is stored for audit, and a final message confirms to Alice that her address will no longer be used. RGPD without drama. One action, three seconds, it's done.
[ORIGINAL DATA] The page is translated into the app's 6 languages (French, English, German, Spanish, Italian, Portuguese). Accented characters were broken in some languages due to an encoding issue in the translation file: fixed in commit 12e61a7.
The Resend webhook: knowing before the user writes
All sends go through Resend, a transactional email provider focused on developer experience. Resend offers webhooks for every event in an email's lifecycle: email.sent, email.delivered, email.opened, email.clicked, email.bounced, email.complained, email.delivery_delayed.
All are listened to and stored in a dedicated table with a reference to the user, email type, timestamp, and associated metadata. This then allows aggregation: how many emails arrived today, how many were opened, which ones generated a click, how many bounced.
The admin dashboard displays these stats in real-time with badges that increment with each send. A bounce appearing for a user? I see it immediately, I can check if it's a temporary problem or a dead email, and adjust. A complaint (marked as spam)? High priority, immediate investigation.
Send history grouped by user, with resend and dedup
The admin sees all recent sends, but grouped by user. If Alice received her verification email, then her D+3 reminder, then her D+7 feedback, I see an "Alice" line with three expandable sub-lines. More readable than a raw chronological feed.
Each send has a "source" badge (auto / manual). Automatic sends (cron, triggers) are differentiated from manual sends (the "resend" button in the admin). A "resend" button exists on each line for cases where an email went to spam, to force a retry to another alias, or to test a template change.
A dedup system prevents re-spamming: if I sent a welcome email 2 hours ago and I want to do a group send "all registrations of the day," Alice is automatically excluded because she has already received it. An "eligible" badge is displayed for each user to indicate whether they can receive the current send or not.
Two parallel mobile hotfixes: v1.07 and v1.08
While the emailing backend was progressing on Vercel, the mobile app needed some air. Two releases went to the Play Store in Alpha, then production.
v1.07 (7d65fd0): 8 targeted bugs, plus a new compact view in folders. When you have 15 sub-folders in a project, you want to see the tree at a glance without scrolling. A toggle switches between detailed view (full cards with thumbnails and previews) and compact view (dense lines with just the name and count). Zero new features in appearance, but a change in usage for heavy users.
v1.08 (a494e7e): complete gesture-handler audit. TAMSIV uses react-native-gesture-handler everywhere, but several screens still had TouchableOpacity or FlatList imported directly from react-native. Result: intermittent taps that didn't register, impossible to reproduce, reported by users who ended up uninstalling without understanding.
The audit touched 25+ files. Every TouchableOpacity, every FlatList, every ScrollView was switched to the gesture-handler import. The phantom tap bug is fixed. Take the opportunity to refactor the feed UI and stabilize all modals: in the process, the polish takes a clear leap.
What I learned after 10 days
What struck me was that every line of code written during these 10 days will remain invisible as long as it works. No one says "wow, your verification email arrived at just the right time, only once, in the correct language." No one notices that a bounce was automatically detected and that the admin saw the signal before the user even wrote.
The invisible is only noticed when it fails. And at that moment, the user doesn't understand what broke: they just understand that the app "isn't working well." They uninstall. They don't write. They don't say why.
So the invisible might be 80% of what makes a finished product. Not the buttons we add in feature releases, not the colors we redo, not the animations. Just the fact that when something needs to reach the user, it arrives. At the right time. Once. In the right language.
It's not sexy to post on LinkedIn. But it's what makes a product stick.
FAQ
Why not use an all-in-one service like Mailchimp or ConvertKit?
Because these are newsletter tools, not transactional ones. They are designed for editorial group sends, not for individual triggers linked to the user lifecycle. Resend is designed for transactional emails (welcome, verification, password reset, feedback loop). It's the right tool for the right job.
Is the Resend webhook reliable for events?
Very reliable. Resend retries webhooks in case of failure, signs payloads for authentication, and exposes a console for manual replay. In 10 days of use, I haven't detected a single lost event.
How do you manage translations for the 6 languages for emails?
Each email template is defined in French, then translated by an automatic script via OpenRouter (LLM). The translation keys live in the same messages/*.json files as the website, with a dedicated emails namespace. The server-side send uses the user's preferred language stored in the database, falling back to English if absent.
Is the anti-impersonation flow abused? Can someone else's account be deleted?
No. The "I didn't create this account" link is signed with a token linked to the target email address. Only the person who receives the email can click it and delete the registration. If someone else tries to call the route without the correct token, it returns a 403 error without doing anything.
Does this system apply to iOS when the app is released?
Yes, it's backend. Emails are sent from Vercel and do not depend on the mobile app platform. The day TAMSIV is released on iOS (12 people have already clicked "Download for iOS" on the website), the email flow will be identical.