Building an email preview and test-send feature in your product
If customers edit email templates in your product, give them a preview and a safe test send. What to render, how to fake data and how to prevent abuse.

On this page(9 sections)
The moment your product lets customers customise an email, such as a welcome message, an invoice template or a notification, you inherit a problem. They will change the text, add a variable, break a link and save, with no idea what the message will look like in a real inbox.
A preview and a test-send button solve most of it. They let people see the result before it goes to a customer, and they cut support questions from "why does my email look broken?" to nothing. They also create new risks if they are built carelessly. This guide covers what to build and what to guard against.
If you are testing your own system's mail rather than building a feature for customers, see testing transactional email in CI and testing email locally with a fake SMTP server.
What a good preview does
A preview is an on-screen rendering of the exact message that would be sent. It should be:
- Accurate. It uses the same rendering code as production, not a separate approximation.
- Instant. It updates as the person edits, or on a quick refresh.
- Realistic. It shows real-looking data in variables, not blank placeholders.
- Honest. It says what it cannot show, such as how a specific mail client will render the message.
The best rule is one renderer, two outputs: the same function produces the preview and the real message. If the two paths drift apart, the preview becomes a lie.
Preview data
A template without data is an empty shell. Show it filled in.
- Sample data that looks real: "Alex Rivera", an order number, a date, an amount. Avoid obvious fake text such as "Lorem ipsum".
- Let the person choose the sample: a short list such as "New customer", "Customer with a long name" and "Order with ten items".
- Show edge cases: a missing optional field, a very long name, special characters and non-English text. Many broken emails are caused by data the author never imagined.
- Highlight unknown variables. If the template uses
{{ first_nam }}, show a clear error beside the preview, not a blank space. See merge variable mistakes for how to treat variables like code. - Never use real customer data in a preview. Use generated samples.
What to render
Show more than the body.
- The envelope details: From name and address, Reply-To, subject and the preheader text that appears in the inbox list.
- An inbox row preview, showing roughly what a mailbox list will display.
- HTML and plain text. Both parts matter. See why the plain-text part matters.
- Desktop and phone widths. Many readers open mail on a phone.
- Dark mode, at least as a toggle that approximates a dark background. Real clients vary, and the limits are explained in HTML rendering constraints for transactional email.
- Links. List every link with its destination, so a person can see where each goes.
Warnings that help
A preview can also check the message.
- Missing subject, From name or unsubscribe link where one is required.
- Images without alt text, or hosted over plain HTTP.
- Very large HTML, which some clients clip.
- Links that use a different domain from the visible text.
- Variables with no sample data.
- Text that is likely to be flagged as spam, though avoid overpromising; see spam filter myths.
Make warnings informational unless they would actually break the message.
The test-send button
A preview shows what you built. A test send shows what arrives. Both are needed, because only a real message tests the whole path: sending, authentication and rendering in a real client.
Design the flow
- Send to the logged-in user by default, using the address they signed up with. Make it one click.
- Allow a few additional addresses that the person has verified, such as colleagues. Do not allow free-form addresses without verification.
- Mark the subject with a clear prefix such as "[Test]", so a test is never mistaken for the real thing.
- Add a visible banner or a header line inside the message: "This is a test of your template."
- Use sample data, as in the preview.
- Show the result. "Test sent to [email protected] at 10:42. It usually arrives within a minute."
Prevent abuse
A test-send endpoint is an email-sending feature open to logged-in users, which is attractive to abusers. The same principles apply as for contact forms.
- Limit recipients. Only send to verified addresses of the account.
- Rate limit per user and per workspace, such as ten tests an hour. See handling 429 responses.
- Do not allow arbitrary content injection into the From or headers. Build the message from the template, not from raw input.
- Use a dedicated sending identity or subdomain for test messages, so a problem does not affect production mail.
- Log who sent what and when.
- Skip tracking in tests, or make sure test opens and clicks do not count as engagement.
Do not send test mail to real customers
Customers should never receive a test. A test mode should never be one flag away from a live send.
- Make the test button and the real send separate actions.
- Disable test sends to recipients outside the allowed set, even for administrators.
- Keep sandbox data away from production lists. See keeping staging from emailing real customers for the same idea at environment level.
Handling different clients honestly
You cannot guarantee how every mail client renders a message. Be clear about it.
- Tell people the preview is a reference, and the test send is the check.
- Offer a link to a rendering service or a note on common differences, rather than promising pixel-perfect results.
- Keep templates simple. Fewer features means fewer differences.
Version history and safe rollout
Customers will break their templates. Make recovery easy.
- Save drafts separately from the live template.
- Keep versions, with a way to restore the last working one. See versioning email templates like code.
- Require a successful preview before publishing, and warn if a test was never sent.
- Show which messages use the template so people know the impact of a change.
Make it fast and clear
- Render on the server and return HTML for the preview, in a sandboxed frame so template code cannot run scripts in your app.
- Cache renders by template version and sample data.
- Show errors next to the line that caused them.
- Add a short note explaining what each warning means.
Key takeaways
- Use one renderer for the preview and the real message, so they cannot drift.
- Preview with realistic sample data, edge cases and both HTML and plain text.
- Add a test-send to verified addresses, clearly marked as a test and rate limited.
- Treat test sending as an abuse-prone feature: limit recipients, log it and keep it away from real customers.
- Make drafts, versions and restores part of the feature, because people will break templates.
Start with Koltrix
Your domain, one inbox, and an API that sends.
A team inbox where AI sorts and drafts (nothing is sent without your click), plus the transactional API and SMTP relay your product sends with. 7 days free, no card.


