Lightweight Postmark email API client for .NET. Send transactional emails, batch emails, templated emails with tracking. Simple async API for email delivery, bounce handling, and delivery statistics. Best Postmark SDK alternative for C# developers.
$ dotnet add package ForeverTools.PostmarkLightweight Postmark email API client for .NET. Send transactional emails, batch emails, and templated emails with delivery tracking.
dotnet add package ForeverTools.Postmark
Sign up at Postmark to get your Server API Token.
using ForeverTools.Postmark;
var client = new PostmarkClient("your-server-token");
// Simple send
var result = await client.SendEmailAsync(
to: "recipient@example.com",
subject: "Hello from Postmark!",
htmlBody: "<h1>Welcome!</h1><p>This is a test email.</p>",
from: "sender@yourdomain.com"
);
if (result.Success)
{
Console.WriteLine($"Sent! Message ID: {result.MessageId}");
}
var email = new PostmarkEmail
{
From = "sender@yourdomain.com",
To = "recipient@example.com",
Subject = "Order Confirmation",
HtmlBody = "<h1>Thank you for your order!</h1>",
TextBody = "Thank you for your order!",
Tag = "order-confirmation",
TrackOpens = true,
TrackLinks = LinkTrackingOptions.HtmlAndText,
Metadata = new Dictionary<string, string>
{
["order_id"] = "12345"
}
};
var result = await client.SendEmailAsync(email);
var emails = new List<PostmarkEmail>
{
new() { From = "sender@yourdomain.com", To = "user1@example.com", Subject = "Hello 1", TextBody = "Hi!" },
new() { From = "sender@yourdomain.com", To = "user2@example.com", Subject = "Hello 2", TextBody = "Hi!" },
new() { From = "sender@yourdomain.com", To = "user3@example.com", Subject = "Hello 3", TextBody = "Hi!" }
};
var results = await client.SendBatchAsync(emails);
foreach (var result in results)
{
Console.WriteLine($"{result.To}: {(result.Success ? "Sent" : result.Message)}");
}
// Using template alias
var result = await client.SendTemplateEmailAsync(
templateIdOrAlias: "welcome-email",
to: "user@example.com",
templateModel: new Dictionary<string, object>
{
["name"] = "John",
["product_name"] = "Awesome App",
["action_url"] = "https://example.com/activate"
},
from: "welcome@yourdomain.com"
);
var email = new PostmarkEmail
{
From = "sender@yourdomain.com",
To = "recipient@example.com",
Subject = "Your Invoice",
TextBody = "Please find your invoice attached.",
Attachments = new List<PostmarkAttachment>
{
PostmarkAttachment.FromFile("invoice.pdf"),
PostmarkAttachment.FromBytes("data.csv", csvBytes, "text/csv")
}
};
await client.SendEmailAsync(email);
// Get delivery overview
var stats = await client.GetDeliveryStatsAsync();
Console.WriteLine($"Inactive emails: {stats.InactiveMails}");
// Get detailed outbound stats
var outbound = await client.GetOutboundStatsAsync(
fromDate: DateTime.UtcNow.AddDays(-30),
toDate: DateTime.UtcNow
);
Console.WriteLine($"Sent: {outbound.Sent}");
Console.WriteLine($"Bounced: {outbound.Bounced}");
Console.WriteLine($"Opens: {outbound.UniqueOpens}");
Console.WriteLine($"Clicks: {outbound.UniqueClicks}");
// Get recent bounces
var bounces = await client.GetBouncesAsync(count: 50);
foreach (var bounce in bounces.Bounces)
{
Console.WriteLine($"{bounce.Email}: {bounce.Type} - {bounce.Description}");
}
// Reactivate a bounced address
var activation = await client.ActivateBounceAsync(bounceId: 123456);
// Program.cs
builder.Services.AddForeverToolsPostmark("your-server-token");
// Or with full configuration
builder.Services.AddForeverToolsPostmark(options =>
{
options.ServerToken = "your-server-token";
options.DefaultFrom = "noreply@yourdomain.com";
options.TrackOpens = true;
options.TrackLinks = "HtmlAndText";
});
// Or from appsettings.json
builder.Services.AddForeverToolsPostmark(builder.Configuration);
// appsettings.json
{
"Postmark": {
"ServerToken": "your-server-token",
"DefaultFrom": "noreply@yourdomain.com",
"TrackOpens": true
}
}
// Inject and use
public class EmailService
{
private readonly PostmarkClient _postmark;
public EmailService(PostmarkClient postmark)
{
_postmark = postmark;
}
public async Task SendWelcomeEmail(string email, string name)
{
await _postmark.SendTemplateEmailAsync(
"welcome-template",
email,
new Dictionary<string, object> { ["name"] = name }
);
}
}
// Uses POSTMARK_SERVER_TOKEN by default
var client = PostmarkClient.FromEnvironment();
// Or specify custom variable name
var client = PostmarkClient.FromEnvironment("MY_POSTMARK_TOKEN");
Postmark separates transactional and marketing emails:
// Transactional (default)
email.MessageStream = MessageStreams.Outbound;
// Marketing/newsletters
email.MessageStream = MessageStreams.Broadcast;
email.TrackLinks = LinkTrackingOptions.None; // No tracking
email.TrackLinks = LinkTrackingOptions.HtmlAndText; // Track all links
email.TrackLinks = LinkTrackingOptions.HtmlOnly; // Track only HTML links
email.TrackLinks = LinkTrackingOptions.TextOnly; // Track only text links
Postmark is designed specifically for transactional email:
MIT License - see LICENSE for details.