I wanted a demo that made email feel less like a black box.
Most "send your first email" examples stop at the moment the API returns queued. That is useful, but it is not the whole developer experience. If you are building onboarding emails, receipts, password resets, billing alerts, or lifecycle notifications, the real question is what happens after the send.
Was it delivered? Did the recipient open it? Did they click? Did it bounce?
So I built a tiny local dashboard for the Telnyx Email API. It sends one email, polls the event feed, and turns the response into delivery, open, click, bounce, and unsubscribe rates.
The full code sample is here:
https://github.com/team-telnyx/telnyx-code-examples/tree/main/setup-email-api-nodejs
What the sample does
The sample is intentionally small:
- one Node.js server
- one HTML page
- no npm dependencies
- a
.envfile for configuration - a local dashboard at
http://localhost:3000
The flow is:
- Read
TELNYX_API_KEY,FROM_EMAIL, andTO_EMAILfrom.env. - Send one email with
POST /v2/email_messages. - Enable open and click tracking for that message.
- Poll message events.
- Render the lifecycle in a browser dashboard.
It is not meant to be a full production analytics app. It is meant to show the full first loop: send, deliver, open, click, observe.
The send request
The core API call is POST /v2/email_messages.
The sample sends a simple HTML email and turns on tracking for this specific message:
tracking_settings: {
open_tracking: true,
click_tracking: true,
}
That detail matters. Delivery events come from the normal Email API lifecycle. Open and click events require tracking. If you omit tracking_settings, the message inherits the sender domain's default tracking settings.
For a first demo, per-send tracking makes the behavior easy to see: send one email, open it, click the link, and watch the dashboard update.
Polling events
Once the API returns a message ID, the app polls:
GET /v2/email_messages/{id}/events
The events look like a timeline:
- queued
- sending
- sent
- delivered
- opened
- clicked
The dashboard turns those events into rates:
- delivery rate
- open rate
- click rate
- bounce rate
- unsubscribe rate
For a one-message demo, a delivered email gives you 100% delivery. Opening it gives you 100% open. Clicking the link gives you 100% click. That makes the lifecycle obvious without needing a large dataset.
Why this is useful
This pattern is useful beyond the demo. If you can send a message and track what happens next, you can build better product workflows:
- onboarding sequences
- transactional receipts
- billing alerts
- password resets
- operational notifications
- lifecycle nudges
- internal delivery dashboards
The same event feed that powers the local dashboard can also power support tooling, alerting, reporting, or customer-facing status views.
Safe for screen sharing
I also wanted the sample to be safe to demo publicly.
The server keeps the API key server-side. The browser only sees masked sender and recipient addresses. Local message IDs are stored in data/sent.json, and that folder is ignored by git. The .env file is ignored too, while .env.example contains placeholders.
That means you can show the app without accidentally exposing the API key or real email addresses.
Try it
Clone the repo:
git clone https://github.com/team-telnyx/telnyx-code-examples.git
cd telnyx-code-examples/setup-email-api-nodejs
Create your env file:
cp .env.example .env
Fill in:
TELNYX_API_KEY=KEY_your_telnyx_api_key_here
FROM_EMAIL=sender@example.com
TO_EMAIL=you@example.com
Start the app:
npm start
Open:
http://localhost:3000
Click Send test email, open the email when it arrives, click the link, and watch the event log update.
What comes next
This sample covers the first end-to-end tracked send. From here, the natural next steps are:
- custom sending domain setup
- DNS verification
- templates
- scheduled sends
- suppression handling
- webhooks
- inbound inboxes and replies
- persistent storage instead of local JSON
But the foundation is the same: send the message, keep the API key safe, and let events tell you what happened.
That is the part I wanted this sample to make visible.
Top comments (0)