Postmark Integration
This page describes how Postmark (a transactional email service) is used in the Position List application. It is split into two parts:
-
Business perspective — what users can do and why Postmark is involved.
-
Technical perspective — how the integration is wired in code.
About Postmark
What is Postmark?
Postmark is a cloud-based SaaS email service provider designed specifically for delivering transactional emails, offering both an SMTP service and a REST API. Founded in 2009, it was acquired by ActiveCampaign in 2022, though it continues to operate as a standalone product focused on transactional email delivery.
Core focus: transactional email
Transactional emails are one-to-one unique messages that the recipient is expecting to receive — usually triggered by a user action and not requiring an unsubscribe link. Common examples include welcome emails, password resets, receipts, and notifications.
Key features
Security
Postmark uses TLS encryption for email transmissions and provides guided setup for SPF, DKIM, and DMARC to protect sender reputation and reduce phishing risk.
Sender Signatures
A Sender Signature is a verification of an individual sender email address, used as an alternative to full domain verification. Before a sender can send email through Postmark, their address must be confirmed via a verification link. This is the mechanism the Position List app uses to validate each user before allowing them to send.
Integration methods
Postmark supports two integration methods:
-
REST API — via
https://api.postmarkapp.com, authenticated with server or account tokens passed as HTTP headers. -
SMTP — a standard SMTP endpoint for apps that prefer that approach.
Official and community SDKs are available for most major languages (.NET, Ruby, Node.js, Python, etc.). Note that the Position List integration uses a custom HttpClient wrapper rather than the official SDK.
Part 1 — Business Perspective
Why Postmark?
The application lets users send exported position lists by email directly from the platform. Postmark is the underlying delivery service that actually sends those emails and reports back on delivery status (delivered, bounced, opened, clicked).
Using Postmark gives the business:
-
A trusted, monitored delivery channel for outbound mail.
-
Per-recipient delivery insight (was it received? opened? clicked?).
-
Verified sender identities so messages are less likely to be flagged as spam.
What Users Can Do
1. Send a position list by email
A user can compose an email (recipients, CC/BCC, subject, rich-text body) with an exported position list embedded, and send it. The email is delivered by Postmark on behalf of the user's verified address.
2. Verify the sender identity (one-time setup)
Before a user can send, their email address must be confirmed as a Postmark Sender Signature:
-
The first time a user tries to send, the app asks Postmark to register their address as a sender.
-
Postmark emails the user a confirmation link.
-
Once the user clicks it, sending is enabled.
If verification has not happened yet, the composer shows an overlay explaining the situation and offers a Re-send verification email action.
3. View email history & delivery events
For any email sent through the app, the user can open a details view that shows:
-
Subject, recipients, and the rendered HTML body.
-
A per-recipient timeline of events: Delivered, Bounced, Opened, Clicked, etc., each with timestamps.
Note: Postmark retains message details for 45 days. Older emails will still show the metadata stored in our database, but the live event timeline will not be available.
4. Manage sender signatures (admin)
Administrators can manage the list of registered sender signatures across the organization, view their confirmation status, and trigger re-sends of verification emails.
5. Distribution lists
Users can save groups of recipients as named distribution lists and reuse them when composing emails. The app expands list names into individual addresses before handing the message to Postmark.
End-to-End User Journey
|
Step |
Unverified path |
Verified path |
|---|---|---|
|
1 |
Compose email |
Compose email |
|
2 |
App detects signature not confirmed → show Postmark overlay |
App confirms signature → send via Postmark |
|
3 |
User triggers re-send of verification email |
Store MessageID + history in DB |
|
4 |
— |
User views per-recipient delivery events |
Operational Notes
-
Two Postmark credentials are used: one for managing senders, one for sending email. Both live in secure configuration; rotation is an ops task.
-
Templates are defined inside Postmark itself (not in the repo). The app references them by numeric template ID.
-
Cost / volume scales with the number of emails sent, since every send is one Postmark API call.
Part 2 — Technical Perspective
High-Level Architecture
React UI ──► MVC Controllers ──► PostmarkHelper ──► Postmark REST API
│
▼
Database
(sender signatures, sent-email history with Postmark MessageID)
The frontend never talks to Postmark directly. All Postmark calls go through two MVC controllers, which delegate to a single helper class.
1. Configuration & Startup
Registered in Infrastructure/Extensions/StartupExtensions.cs:121:
builder.Services.AddScoped<PostmarkHelper>();
Two secrets are read from configuration:
|
Key |
Used for |
|---|---|
|
|
Sender-signature endpoints ( |
|
|
Email-sending and message-detail endpoints ( |
In dev, these come from secure.config at C:\WebDocs\AppData\PL.env (StartupExtensions.cs:40-41).
2. Server-Side Helper
Common/Helper/PostmarkHelper.cs is a custom HttpClient wrapper — the official Postmark SDK is not used. Base URL: https://api.postmarkapp.com.
|
Method |
Postmark Endpoint |
Purpose |
|---|---|---|
|
|
|
Create a verified sender |
|
|
|
Read signature / verification status |
|
|
|
Resend verification email |
|
|
|
Send position list (main template) |
|
|
|
Send via custom template |
|
|
|
Fetch delivery events |
Auth headers:
-
X-Postmark-Account-Token— for/senders/* -
X-Postmark-Server-Token— for/email/*and/messages/*
Returns an OperationResult wrapper with Success and Result (raw JSON). Failures are logged via Serilog (PostmarkHelper.cs:178).
3. DTOs
-
PostmarkEmailTemplate.cs—TemplateId/TemplateAlias,TemplateModel,From/To/Cc/Bcc/ReplyTo,TrackOpens/TrackLinks,Headers,Attachments. -
PostmarkSenderSignature.cs—EmailAddress,Name,ID,Confirmed,Domain. -
PostmarkMessageDetails.cs—HtmlBody,Subject,From,Status, recipients, andMessageEvents(delivery, bounce, open, click with timestamps).
4. Business Layer
-
Business/PositionList/SenderSignatureBusiness.cs— DB-side CRUD for signatures (uspGetSendersSignatures), current-user signature, and HTML email-signature management. Does not call Postmark directly. -
Business/PositionList/ExportFormatBusiness.cs—PersistSentEmailWithExportedList()saves the PostmarkMessageIDso the UI can later fetch delivery events.
5. MVC Controllers (Frontend-Facing API)
SendersSignaturesController.cs
|
Route |
Purpose |
|---|---|
|
|
List signatures (admin) |
|
|
Single signature details |
|
|
Create/update; calls |
|
|
Resend verification (or create if missing) |
|
|
User HTML email signature |
ExportFormatsController.cs
|
Route |
Purpose |
|---|---|
|
|
Confirms user signature; auto-creates if missing |
|
|
Sends an email + persists history |
|
|
Trigger resend of verification |
|
|
Fetch sent email + Postmark events |
6. Frontend
React: email-export-editor
|
Component |
Role |
|---|---|
|
|
Top-level orchestrator; exposes |
|
|
Single floating composer (To/Cc/Bcc/Subject + TinyMCE body); calls |
|
|
Renders Postmark event timeline grouped by recipient; falls back when email is older than Postmark's 45-day retention |
|
|
Explains the verification step and triggers |
API Client: api.ts
Functions: isPostmarkActive(), sendEmail(), resendSignatureEmail(), getEmailHistoryDetails(), getEmailSignature(), saveEmailSignature().
Hooks
-
useSharedData.ts— bootsisPostmarkActive, distribution lists, and signature; listens for legacy jQuery PubSub events. -
useEmailEditors.ts— manages up to 3 floating editors, SharedWorker cross-tab sync, sessionStorage drafts, and list-injection from exports.
Legacy JS
-
EmailExportEditor.js— old composer; mostly delegates to React now. -
EmailedExportedListDetailsModal.js— legacy details + events timeline. -
EmailSignaturesAdminPanel.js— admin signatures UI.
7. End-to-End Technical Flows
Send a position list
-
UI calls
IsPostmarkActive. -
UI calls
SendEmailwith recipients, subject, HTML body. -
Controller calls
PostmarkHelper.SendEmailWithEmailTemplateOwnerPositionTemplate. -
Postmark
MessageIDis persisted in the DB viaExportFormatBusiness.
Verify sender signature
-
First send creates a Postmark sender via
CreateSenderSignature. -
User confirms the verification email.
-
IsPostmarkActiveflips totrueon the next call.
View delivery events
-
UI calls
GetEmailedExportedListDetails. -
Controller calls
PostmarkHelper.GetMessageDetailswith the storedMessageID. -
UI renders
MessageEventsgrouped per recipient.
Resend verification
PostmarkOverlay → ResendSignatureEmail → PostmarkHelper.ResendSignatureEmail
Distribution lists
[ListName] tokens in recipient fields are expanded server-side (FillDistributionLists) before the Postmark call.
8. Summary
|
Concern |
Detail |
|---|---|
|
Integration point |
|
|
Tokens |
Account (signatures) and Server (sending / messages) |
|
Templates |
|
|
Frontend contact |
React + legacy JS talk only to two MVC controllers — never directly to Postmark |