chub-dev 0.1.0 → 0.1.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1168 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: transactional-email
|
|
3
|
+
description: "Postmark API coding guidelines for transactional email sending using the official Node.js library"
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "4.0.5"
|
|
7
|
+
updated-on: "2026-03-02"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "postmark,email,transactional,delivery,smtp"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Postmark API Coding Guidelines (JavaScript/TypeScript)
|
|
13
|
+
|
|
14
|
+
You are a Postmark API coding expert. Help me with writing code using the official Postmark Node.js library for transactional email sending and API interactions.
|
|
15
|
+
|
|
16
|
+
You can find the official documentation and code samples here: https://postmarkapp.com/developer
|
|
17
|
+
|
|
18
|
+
## Golden Rule: Use the Correct and Current Package
|
|
19
|
+
|
|
20
|
+
Always use the official Postmark Node.js library, which provides complete support for the entire Postmark REST API.
|
|
21
|
+
|
|
22
|
+
- **Library Name:** Postmark Node.js Library
|
|
23
|
+
- **NPM Package:** `postmark`
|
|
24
|
+
- **Minimum Node.js Version:** v14.0.0
|
|
25
|
+
- **Repository:** https://github.com/ActiveCampaign/postmark.js
|
|
26
|
+
- **Documentation:** https://activecampaign.github.io/postmark.js/
|
|
27
|
+
|
|
28
|
+
**Installation:**
|
|
29
|
+
|
|
30
|
+
- **Correct:** `npm install postmark`
|
|
31
|
+
|
|
32
|
+
**APIs and Usage:**
|
|
33
|
+
|
|
34
|
+
- **Correct:** `const postmark = require('postmark')`
|
|
35
|
+
- **Correct:** `const client = new postmark.ServerClient(serverToken)`
|
|
36
|
+
- **Correct:** `const accountClient = new postmark.AccountClient(accountToken)`
|
|
37
|
+
- **Correct:** `await client.sendEmail(...)`
|
|
38
|
+
- **Correct:** `await client.sendEmailWithTemplate(...)`
|
|
39
|
+
- **Correct:** `await client.sendEmailBatch(...)`
|
|
40
|
+
- **Incorrect:** Using unofficial packages or legacy libraries
|
|
41
|
+
|
|
42
|
+
## API Keys and Authentication
|
|
43
|
+
|
|
44
|
+
Postmark uses two types of API tokens for different purposes:
|
|
45
|
+
|
|
46
|
+
### Server API Token
|
|
47
|
+
|
|
48
|
+
Used for sending emails and accessing server-specific endpoints. Set the `X-Postmark-Server-Token` header for API requests.
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
const postmark = require('postmark');
|
|
52
|
+
const serverToken = process.env.POSTMARK_SERVER_TOKEN;
|
|
53
|
+
const client = new postmark.ServerClient(serverToken);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Account API Token
|
|
57
|
+
|
|
58
|
+
Used for managing servers and account-level operations. Set the `X-Postmark-Account-Token` header for API requests.
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
const postmark = require('postmark');
|
|
62
|
+
const accountToken = process.env.POSTMARK_ACCOUNT_TOKEN;
|
|
63
|
+
const accountClient = new postmark.AccountClient(accountToken);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Environment Variable Configuration
|
|
67
|
+
|
|
68
|
+
Never hardcode API keys. Always use environment variables:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
echo "export POSTMARK_SERVER_TOKEN='YOUR_SERVER_TOKEN'" > postmark.env
|
|
72
|
+
echo "export POSTMARK_ACCOUNT_TOKEN='YOUR_ACCOUNT_TOKEN'" >> postmark.env
|
|
73
|
+
echo "postmark.env" >> .gitignore
|
|
74
|
+
source ./postmark.env
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Prerequisites
|
|
82
|
+
|
|
83
|
+
Before sending emails with Postmark:
|
|
84
|
+
|
|
85
|
+
- Sign up for a Postmark account (free tier: 100 emails/month)
|
|
86
|
+
- Create a server in your Postmark account
|
|
87
|
+
- Verify your sender signature or domain
|
|
88
|
+
- Obtain your Server API token from the API Tokens tab
|
|
89
|
+
|
|
90
|
+
## Basic Email Sending
|
|
91
|
+
|
|
92
|
+
### Simple Email
|
|
93
|
+
|
|
94
|
+
Send a basic email with HTML and text body:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
const postmark = require('postmark');
|
|
98
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
99
|
+
|
|
100
|
+
client.sendEmail({
|
|
101
|
+
From: 'sender@example.com',
|
|
102
|
+
To: 'recipient@example.com',
|
|
103
|
+
Subject: 'Hello from Postmark',
|
|
104
|
+
HtmlBody: '<strong>Hello!</strong> This is a test email.',
|
|
105
|
+
TextBody: 'Hello! This is a test email.'
|
|
106
|
+
}).then(response => {
|
|
107
|
+
console.log('Email sent successfully');
|
|
108
|
+
console.log('Message ID:', response.MessageID);
|
|
109
|
+
console.log('To:', response.To);
|
|
110
|
+
console.log('Submitted at:', response.SubmittedAt);
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Using async/await
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const postmark = require('postmark');
|
|
118
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
119
|
+
|
|
120
|
+
async function sendEmail() {
|
|
121
|
+
try {
|
|
122
|
+
const response = await client.sendEmail({
|
|
123
|
+
From: 'sender@example.com',
|
|
124
|
+
To: 'recipient@example.com',
|
|
125
|
+
Subject: 'Hello from Postmark',
|
|
126
|
+
HtmlBody: '<h1>Welcome!</h1><p>This is a test email.</p>',
|
|
127
|
+
TextBody: 'Welcome! This is a test email.'
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
console.log('Email sent:', response.MessageID);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error('Error sending email:', error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
sendEmail();
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Multiple Recipients
|
|
140
|
+
|
|
141
|
+
Send to multiple recipients in the To, Cc, or Bcc fields:
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
client.sendEmail({
|
|
145
|
+
From: 'sender@example.com',
|
|
146
|
+
To: 'recipient1@example.com, recipient2@example.com',
|
|
147
|
+
Cc: 'cc1@example.com, cc2@example.com',
|
|
148
|
+
Bcc: 'bcc1@example.com, bcc2@example.com',
|
|
149
|
+
Subject: 'Multiple recipients',
|
|
150
|
+
HtmlBody: '<p>This email goes to multiple people.</p>',
|
|
151
|
+
TextBody: 'This email goes to multiple people.'
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Note:** Maximum 50 recipients per field (To, Cc, Bcc).
|
|
156
|
+
|
|
157
|
+
### With Reply-To Address
|
|
158
|
+
|
|
159
|
+
Override the reply address:
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
client.sendEmail({
|
|
163
|
+
From: 'noreply@example.com',
|
|
164
|
+
To: 'customer@example.com',
|
|
165
|
+
ReplyTo: 'support@example.com',
|
|
166
|
+
Subject: 'Customer Support',
|
|
167
|
+
HtmlBody: '<p>Reply to this email for support.</p>',
|
|
168
|
+
TextBody: 'Reply to this email for support.'
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Batch Email Sending
|
|
173
|
+
|
|
174
|
+
Send up to 500 emails in a single API call (maximum 50 MB payload):
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const postmark = require('postmark');
|
|
178
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
179
|
+
|
|
180
|
+
client.sendEmailBatch([
|
|
181
|
+
{
|
|
182
|
+
From: 'sender@example.com',
|
|
183
|
+
To: 'user1@example.com',
|
|
184
|
+
Subject: 'Welcome User 1',
|
|
185
|
+
HtmlBody: '<p>Welcome to our service!</p>',
|
|
186
|
+
TextBody: 'Welcome to our service!'
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
From: 'sender@example.com',
|
|
190
|
+
To: 'user2@example.com',
|
|
191
|
+
Subject: 'Welcome User 2',
|
|
192
|
+
HtmlBody: '<p>Welcome to our service!</p>',
|
|
193
|
+
TextBody: 'Welcome to our service!'
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
From: 'sender@example.com',
|
|
197
|
+
To: 'user3@example.com',
|
|
198
|
+
Subject: 'Welcome User 3',
|
|
199
|
+
HtmlBody: '<p>Welcome to our service!</p>',
|
|
200
|
+
TextBody: 'Welcome to our service!'
|
|
201
|
+
}
|
|
202
|
+
]).then(responses => {
|
|
203
|
+
responses.forEach((response, index) => {
|
|
204
|
+
console.log(`Email ${index + 1}:`, response.Message);
|
|
205
|
+
console.log('Message ID:', response.MessageID);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Important:** Batch requests return HTTP 200 even if individual messages fail validation. Always check each response for error codes.
|
|
211
|
+
|
|
212
|
+
## Template Emails
|
|
213
|
+
|
|
214
|
+
### Send Email with Template ID
|
|
215
|
+
|
|
216
|
+
Send an email using a pre-created template:
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
const postmark = require('postmark');
|
|
220
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
221
|
+
|
|
222
|
+
client.sendEmailWithTemplate({
|
|
223
|
+
From: 'sender@example.com',
|
|
224
|
+
To: 'recipient@example.com',
|
|
225
|
+
TemplateId: 123456,
|
|
226
|
+
TemplateModel: {
|
|
227
|
+
name: 'John Doe',
|
|
228
|
+
product_name: 'Awesome App',
|
|
229
|
+
action_url: 'https://example.com/verify',
|
|
230
|
+
company_name: 'My Company'
|
|
231
|
+
}
|
|
232
|
+
}).then(response => {
|
|
233
|
+
console.log('Template email sent:', response.MessageID);
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Send Email with Template Alias
|
|
238
|
+
|
|
239
|
+
Use a template alias instead of numeric ID:
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
client.sendEmailWithTemplate({
|
|
243
|
+
From: 'sender@example.com',
|
|
244
|
+
To: 'recipient@example.com',
|
|
245
|
+
TemplateAlias: 'welcome-email',
|
|
246
|
+
TemplateModel: {
|
|
247
|
+
user_name: 'Jane Smith',
|
|
248
|
+
login_url: 'https://example.com/login'
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Batch Template Emails
|
|
254
|
+
|
|
255
|
+
Send multiple template-based emails:
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
client.sendEmailBatchWithTemplates([
|
|
259
|
+
{
|
|
260
|
+
From: 'sender@example.com',
|
|
261
|
+
To: 'user1@example.com',
|
|
262
|
+
TemplateId: 123456,
|
|
263
|
+
TemplateModel: {
|
|
264
|
+
name: 'User One',
|
|
265
|
+
code: 'ABC123'
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
From: 'sender@example.com',
|
|
270
|
+
To: 'user2@example.com',
|
|
271
|
+
TemplateAlias: 'welcome-email',
|
|
272
|
+
TemplateModel: {
|
|
273
|
+
name: 'User Two',
|
|
274
|
+
code: 'DEF456'
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
]).then(responses => {
|
|
278
|
+
responses.forEach((response, index) => {
|
|
279
|
+
console.log(`Template email ${index + 1}:`, response.Message);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Advanced Email Features
|
|
285
|
+
|
|
286
|
+
### Tags and Metadata
|
|
287
|
+
|
|
288
|
+
Add tags for categorization and metadata for custom tracking:
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
client.sendEmail({
|
|
292
|
+
From: 'sender@example.com',
|
|
293
|
+
To: 'recipient@example.com',
|
|
294
|
+
Subject: 'Order Confirmation',
|
|
295
|
+
HtmlBody: '<p>Your order has been confirmed.</p>',
|
|
296
|
+
TextBody: 'Your order has been confirmed.',
|
|
297
|
+
Tag: 'order-confirmation',
|
|
298
|
+
Metadata: {
|
|
299
|
+
order_id: '12345',
|
|
300
|
+
customer_id: '67890',
|
|
301
|
+
total_amount: '99.99'
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Metadata notes:**
|
|
307
|
+
- Maximum 1000 characters per tag
|
|
308
|
+
- Metadata appears in webhooks and API responses
|
|
309
|
+
- Useful for tracking and filtering messages
|
|
310
|
+
|
|
311
|
+
### Tracking Opens
|
|
312
|
+
|
|
313
|
+
Enable open tracking to know when recipients open emails:
|
|
314
|
+
|
|
315
|
+
```javascript
|
|
316
|
+
client.sendEmail({
|
|
317
|
+
From: 'sender@example.com',
|
|
318
|
+
To: 'recipient@example.com',
|
|
319
|
+
Subject: 'Track opens',
|
|
320
|
+
HtmlBody: '<p>This email tracks opens.</p>',
|
|
321
|
+
TextBody: 'This email tracks opens.',
|
|
322
|
+
TrackOpens: true
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Tracking Links
|
|
327
|
+
|
|
328
|
+
Track clicks on links in your emails:
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
client.sendEmail({
|
|
332
|
+
From: 'sender@example.com',
|
|
333
|
+
To: 'recipient@example.com',
|
|
334
|
+
Subject: 'Track links',
|
|
335
|
+
HtmlBody: '<p>Click <a href="https://example.com">here</a>.</p>',
|
|
336
|
+
TextBody: 'Click here: https://example.com',
|
|
337
|
+
TrackLinks: 'HtmlAndText'
|
|
338
|
+
});
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**TrackLinks options:**
|
|
342
|
+
- `'None'` - No link tracking
|
|
343
|
+
- `'HtmlOnly'` - Track links in HTML body only
|
|
344
|
+
- `'TextOnly'` - Track links in text body only
|
|
345
|
+
- `'HtmlAndText'` - Track links in both bodies
|
|
346
|
+
|
|
347
|
+
### Message Streams
|
|
348
|
+
|
|
349
|
+
Organize emails by type using message streams:
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
client.sendEmail({
|
|
353
|
+
From: 'sender@example.com',
|
|
354
|
+
To: 'recipient@example.com',
|
|
355
|
+
Subject: 'Newsletter',
|
|
356
|
+
HtmlBody: '<p>Monthly newsletter content.</p>',
|
|
357
|
+
TextBody: 'Monthly newsletter content.',
|
|
358
|
+
MessageStream: 'broadcasts'
|
|
359
|
+
});
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Default streams:**
|
|
363
|
+
- `'outbound'` - Transactional emails (default)
|
|
364
|
+
- `'broadcasts'` - Marketing/bulk emails
|
|
365
|
+
- Custom streams can be created in your Postmark account
|
|
366
|
+
|
|
367
|
+
## Attachments
|
|
368
|
+
|
|
369
|
+
### Basic Attachments
|
|
370
|
+
|
|
371
|
+
Attach files using Base64 encoding:
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
const fs = require('fs');
|
|
375
|
+
const postmark = require('postmark');
|
|
376
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
377
|
+
|
|
378
|
+
const fileContent = fs.readFileSync('/path/to/document.pdf');
|
|
379
|
+
const base64Content = fileContent.toString('base64');
|
|
380
|
+
|
|
381
|
+
client.sendEmail({
|
|
382
|
+
From: 'sender@example.com',
|
|
383
|
+
To: 'recipient@example.com',
|
|
384
|
+
Subject: 'Document attached',
|
|
385
|
+
HtmlBody: '<p>Please see the attached document.</p>',
|
|
386
|
+
TextBody: 'Please see the attached document.',
|
|
387
|
+
Attachments: [
|
|
388
|
+
{
|
|
389
|
+
Name: 'document.pdf',
|
|
390
|
+
Content: base64Content,
|
|
391
|
+
ContentType: 'application/pdf'
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
});
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Using Postmark Models
|
|
398
|
+
|
|
399
|
+
Use the built-in `Attachment` model for cleaner code:
|
|
400
|
+
|
|
401
|
+
```javascript
|
|
402
|
+
const fs = require('fs');
|
|
403
|
+
const postmark = require('postmark');
|
|
404
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
405
|
+
|
|
406
|
+
const message = new postmark.Models.Message(
|
|
407
|
+
'sender@example.com',
|
|
408
|
+
'Document attached',
|
|
409
|
+
'<p>Please see the attached files.</p>',
|
|
410
|
+
'Please see the attached files.',
|
|
411
|
+
'recipient@example.com'
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
const attachment1 = new postmark.Models.Attachment(
|
|
415
|
+
'report.txt',
|
|
416
|
+
Buffer.from('Report content here').toString('base64'),
|
|
417
|
+
'text/plain'
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
const attachment2 = new postmark.Models.Attachment(
|
|
421
|
+
'invoice.pdf',
|
|
422
|
+
fs.readFileSync('/path/to/invoice.pdf').toString('base64'),
|
|
423
|
+
'application/pdf'
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
message.Attachments = [attachment1, attachment2];
|
|
427
|
+
|
|
428
|
+
client.sendEmail(message);
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### Multiple Attachments
|
|
432
|
+
|
|
433
|
+
```javascript
|
|
434
|
+
const attachments = [
|
|
435
|
+
{
|
|
436
|
+
Name: 'image.jpg',
|
|
437
|
+
Content: fs.readFileSync('/path/to/image.jpg').toString('base64'),
|
|
438
|
+
ContentType: 'image/jpeg'
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
Name: 'spreadsheet.xlsx',
|
|
442
|
+
Content: fs.readFileSync('/path/to/data.xlsx').toString('base64'),
|
|
443
|
+
ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
Name: 'notes.txt',
|
|
447
|
+
Content: Buffer.from('Meeting notes...').toString('base64'),
|
|
448
|
+
ContentType: 'text/plain'
|
|
449
|
+
}
|
|
450
|
+
];
|
|
451
|
+
|
|
452
|
+
client.sendEmail({
|
|
453
|
+
From: 'sender@example.com',
|
|
454
|
+
To: 'recipient@example.com',
|
|
455
|
+
Subject: 'Multiple attachments',
|
|
456
|
+
HtmlBody: '<p>Three files attached.</p>',
|
|
457
|
+
TextBody: 'Three files attached.',
|
|
458
|
+
Attachments: attachments
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Inline Images
|
|
463
|
+
|
|
464
|
+
Embed images directly in HTML emails using Content ID (CID):
|
|
465
|
+
|
|
466
|
+
```javascript
|
|
467
|
+
const fs = require('fs');
|
|
468
|
+
const postmark = require('postmark');
|
|
469
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
470
|
+
|
|
471
|
+
const message = new postmark.Models.Message(
|
|
472
|
+
'sender@example.com',
|
|
473
|
+
'Inline image example',
|
|
474
|
+
'<!DOCTYPE html><html><body><h1>Logo</h1><img src="cid:logo.png"/></body></html>',
|
|
475
|
+
'Logo image included.',
|
|
476
|
+
'recipient@example.com'
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
const inlineImage = new postmark.Models.Attachment(
|
|
480
|
+
'logo.png',
|
|
481
|
+
fs.readFileSync('/path/to/logo.png').toString('base64'),
|
|
482
|
+
'image/png',
|
|
483
|
+
'cid:logo.png'
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
message.Attachments = [inlineImage];
|
|
487
|
+
|
|
488
|
+
client.sendEmail(message);
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## Custom Headers
|
|
492
|
+
|
|
493
|
+
Add custom email headers:
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
const postmark = require('postmark');
|
|
497
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
498
|
+
|
|
499
|
+
const message = new postmark.Models.Message(
|
|
500
|
+
'sender@example.com',
|
|
501
|
+
'Custom headers',
|
|
502
|
+
'<p>Email with custom headers.</p>',
|
|
503
|
+
'Email with custom headers.',
|
|
504
|
+
'recipient@example.com'
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
message.Headers = [
|
|
508
|
+
{ Name: 'X-Custom-Header', Value: 'custom-value' },
|
|
509
|
+
{ Name: 'X-Priority', Value: '1' },
|
|
510
|
+
{ Name: 'X-Campaign-ID', Value: 'summer-2025' }
|
|
511
|
+
];
|
|
512
|
+
|
|
513
|
+
client.sendEmail(message);
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
## Template Management
|
|
517
|
+
|
|
518
|
+
### Get Template
|
|
519
|
+
|
|
520
|
+
Retrieve a template by ID or alias:
|
|
521
|
+
|
|
522
|
+
```javascript
|
|
523
|
+
// By template ID
|
|
524
|
+
client.getTemplate(123456).then(template => {
|
|
525
|
+
console.log('Template name:', template.Name);
|
|
526
|
+
console.log('Template alias:', template.Alias);
|
|
527
|
+
console.log('HTML body:', template.HtmlBody);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// By template alias
|
|
531
|
+
client.getTemplate('welcome-email').then(template => {
|
|
532
|
+
console.log('Template:', template);
|
|
533
|
+
});
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Create Template
|
|
537
|
+
|
|
538
|
+
```javascript
|
|
539
|
+
client.createTemplate({
|
|
540
|
+
Name: 'Welcome Email',
|
|
541
|
+
Alias: 'welcome-email',
|
|
542
|
+
Subject: 'Welcome to {{company_name}}!',
|
|
543
|
+
HtmlBody: '<h1>Welcome {{user_name}}!</h1><p>Thanks for joining.</p>',
|
|
544
|
+
TextBody: 'Welcome {{user_name}}! Thanks for joining.'
|
|
545
|
+
}).then(template => {
|
|
546
|
+
console.log('Created template ID:', template.TemplateId);
|
|
547
|
+
});
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Edit Template
|
|
551
|
+
|
|
552
|
+
```javascript
|
|
553
|
+
client.editTemplate(123456, {
|
|
554
|
+
Name: 'Updated Welcome Email',
|
|
555
|
+
Subject: 'Welcome to {{company_name}}, {{user_name}}!',
|
|
556
|
+
HtmlBody: '<h1>Hi {{user_name}}!</h1><p>Welcome to {{company_name}}.</p>',
|
|
557
|
+
TextBody: 'Hi {{user_name}}! Welcome to {{company_name}}.'
|
|
558
|
+
}).then(template => {
|
|
559
|
+
console.log('Updated template:', template.Name);
|
|
560
|
+
});
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Delete Template
|
|
564
|
+
|
|
565
|
+
```javascript
|
|
566
|
+
// By template ID
|
|
567
|
+
client.deleteTemplate(123456).then(response => {
|
|
568
|
+
console.log('Template deleted:', response.Message);
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// By template alias
|
|
572
|
+
client.deleteTemplate('old-template').then(response => {
|
|
573
|
+
console.log('Template deleted:', response.Message);
|
|
574
|
+
});
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### List Templates
|
|
578
|
+
|
|
579
|
+
```javascript
|
|
580
|
+
client.getTemplates({
|
|
581
|
+
Count: 10,
|
|
582
|
+
Offset: 0
|
|
583
|
+
}).then(result => {
|
|
584
|
+
console.log('Total templates:', result.TotalCount);
|
|
585
|
+
result.Templates.forEach(template => {
|
|
586
|
+
console.log('Template:', template.Name, '(ID:', template.TemplateId + ')');
|
|
587
|
+
});
|
|
588
|
+
});
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### Validate Template
|
|
592
|
+
|
|
593
|
+
Test template rendering before sending:
|
|
594
|
+
|
|
595
|
+
```javascript
|
|
596
|
+
client.validateTemplate({
|
|
597
|
+
Subject: 'Hello {{name}}',
|
|
598
|
+
HtmlBody: '<p>Welcome {{name}} to {{company}}!</p>',
|
|
599
|
+
TextBody: 'Welcome {{name}} to {{company}}!',
|
|
600
|
+
TestRenderModel: {
|
|
601
|
+
name: 'John',
|
|
602
|
+
company: 'Acme Corp'
|
|
603
|
+
}
|
|
604
|
+
}).then(result => {
|
|
605
|
+
console.log('Rendered subject:', result.Subject.RenderedContent);
|
|
606
|
+
console.log('Rendered HTML:', result.HtmlBody.RenderedContent);
|
|
607
|
+
console.log('Suggested template model:', result.SuggestedTemplateModel);
|
|
608
|
+
});
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
## Messages API
|
|
612
|
+
|
|
613
|
+
### Get Outbound Messages
|
|
614
|
+
|
|
615
|
+
Retrieve sent messages with filtering:
|
|
616
|
+
|
|
617
|
+
```javascript
|
|
618
|
+
client.getOutboundMessages({
|
|
619
|
+
Count: 50,
|
|
620
|
+
Offset: 0,
|
|
621
|
+
Recipient: 'user@example.com',
|
|
622
|
+
FromEmail: 'sender@example.com',
|
|
623
|
+
Tag: 'order-confirmation',
|
|
624
|
+
Status: 'sent'
|
|
625
|
+
}).then(result => {
|
|
626
|
+
console.log('Total messages:', result.TotalCount);
|
|
627
|
+
result.Messages.forEach(message => {
|
|
628
|
+
console.log('Message ID:', message.MessageID);
|
|
629
|
+
console.log('Subject:', message.Subject);
|
|
630
|
+
console.log('Status:', message.Status);
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### Get Message Details
|
|
636
|
+
|
|
637
|
+
```javascript
|
|
638
|
+
client.getOutboundMessageDetails('message-id-here').then(details => {
|
|
639
|
+
console.log('From:', details.From);
|
|
640
|
+
console.log('To:', details.To);
|
|
641
|
+
console.log('Subject:', details.Subject);
|
|
642
|
+
console.log('Status:', details.Status);
|
|
643
|
+
console.log('Received at:', details.ReceivedAt);
|
|
644
|
+
console.log('Message events:', details.MessageEvents);
|
|
645
|
+
});
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### Get Message Dump
|
|
649
|
+
|
|
650
|
+
Retrieve full message content including headers:
|
|
651
|
+
|
|
652
|
+
```javascript
|
|
653
|
+
client.getOutboundMessageDump('message-id-here').then(dump => {
|
|
654
|
+
console.log('Raw message:', dump.Body);
|
|
655
|
+
});
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
### Get Message Clicks
|
|
659
|
+
|
|
660
|
+
Track which links were clicked:
|
|
661
|
+
|
|
662
|
+
```javascript
|
|
663
|
+
client.getMessageClicks('message-id-here').then(result => {
|
|
664
|
+
result.Clicks.forEach(click => {
|
|
665
|
+
console.log('Link:', click.OriginalLink);
|
|
666
|
+
console.log('Clicked at:', click.RecordedAt);
|
|
667
|
+
console.log('Platform:', click.Platform);
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### Get Message Opens
|
|
673
|
+
|
|
674
|
+
Track when messages were opened:
|
|
675
|
+
|
|
676
|
+
```javascript
|
|
677
|
+
client.getMessageOpens('message-id-here').then(result => {
|
|
678
|
+
result.Opens.forEach(open => {
|
|
679
|
+
console.log('Opened at:', open.RecordedAt);
|
|
680
|
+
console.log('Platform:', open.Platform);
|
|
681
|
+
console.log('Client:', open.Client);
|
|
682
|
+
});
|
|
683
|
+
});
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
## Inbound Email Processing
|
|
687
|
+
|
|
688
|
+
### Get Inbound Messages
|
|
689
|
+
|
|
690
|
+
Retrieve inbound emails sent to your Postmark inbox:
|
|
691
|
+
|
|
692
|
+
```javascript
|
|
693
|
+
client.getInboundMessages({
|
|
694
|
+
Count: 50,
|
|
695
|
+
Offset: 0,
|
|
696
|
+
Recipient: 'inbox@inbound.example.com',
|
|
697
|
+
FromEmail: 'sender@example.com'
|
|
698
|
+
}).then(result => {
|
|
699
|
+
console.log('Total inbound messages:', result.TotalCount);
|
|
700
|
+
result.InboundMessages.forEach(message => {
|
|
701
|
+
console.log('From:', message.From);
|
|
702
|
+
console.log('Subject:', message.Subject);
|
|
703
|
+
console.log('Received:', message.ReceivedAt);
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
### Get Inbound Message Details
|
|
709
|
+
|
|
710
|
+
```javascript
|
|
711
|
+
client.getInboundMessageDetails('inbound-message-id').then(message => {
|
|
712
|
+
console.log('From:', message.From);
|
|
713
|
+
console.log('To:', message.To);
|
|
714
|
+
console.log('Subject:', message.Subject);
|
|
715
|
+
console.log('HTML body:', message.HtmlBody);
|
|
716
|
+
console.log('Text body:', message.TextBody);
|
|
717
|
+
console.log('Attachments:', message.Attachments);
|
|
718
|
+
});
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### Bypass Blocked Inbound Message
|
|
722
|
+
|
|
723
|
+
Allow specific blocked inbound messages:
|
|
724
|
+
|
|
725
|
+
```javascript
|
|
726
|
+
client.bypassBlockedInboundMessage('inbound-message-id').then(response => {
|
|
727
|
+
console.log('Message unblocked:', response.Message);
|
|
728
|
+
});
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Retry Inbound Hook
|
|
732
|
+
|
|
733
|
+
Manually retry webhook delivery for an inbound message:
|
|
734
|
+
|
|
735
|
+
```javascript
|
|
736
|
+
client.retryInboundHookForMessage('inbound-message-id').then(response => {
|
|
737
|
+
console.log('Hook retried:', response.Message);
|
|
738
|
+
});
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
## Bounce Management
|
|
742
|
+
|
|
743
|
+
### Get Bounces
|
|
744
|
+
|
|
745
|
+
Retrieve bounced emails:
|
|
746
|
+
|
|
747
|
+
```javascript
|
|
748
|
+
client.getBounces({
|
|
749
|
+
Count: 50,
|
|
750
|
+
Offset: 0,
|
|
751
|
+
Type: 'HardBounce',
|
|
752
|
+
EmailFilter: 'user@example.com',
|
|
753
|
+
Tag: 'newsletter'
|
|
754
|
+
}).then(result => {
|
|
755
|
+
console.log('Total bounces:', result.TotalCount);
|
|
756
|
+
result.Bounces.forEach(bounce => {
|
|
757
|
+
console.log('Email:', bounce.Email);
|
|
758
|
+
console.log('Type:', bounce.Type);
|
|
759
|
+
console.log('Bounced at:', bounce.BouncedAt);
|
|
760
|
+
});
|
|
761
|
+
});
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Get Bounce Details
|
|
765
|
+
|
|
766
|
+
```javascript
|
|
767
|
+
client.getBounce('bounce-id').then(bounce => {
|
|
768
|
+
console.log('Email:', bounce.Email);
|
|
769
|
+
console.log('Type:', bounce.Type);
|
|
770
|
+
console.log('Description:', bounce.Description);
|
|
771
|
+
console.log('Details:', bounce.Details);
|
|
772
|
+
});
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Get Bounce Dump
|
|
776
|
+
|
|
777
|
+
Retrieve raw bounce message:
|
|
778
|
+
|
|
779
|
+
```javascript
|
|
780
|
+
client.getBounceDump('bounce-id').then(dump => {
|
|
781
|
+
console.log('Raw bounce:', dump.Body);
|
|
782
|
+
});
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Activate Bounced Email
|
|
786
|
+
|
|
787
|
+
Reactivate a bounced email address:
|
|
788
|
+
|
|
789
|
+
```javascript
|
|
790
|
+
client.activateBounce('bounce-id').then(response => {
|
|
791
|
+
console.log('Bounce activated:', response.Message);
|
|
792
|
+
});
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
## Suppressions Management
|
|
796
|
+
|
|
797
|
+
### Get Suppressions
|
|
798
|
+
|
|
799
|
+
Retrieve suppressed email addresses:
|
|
800
|
+
|
|
801
|
+
```javascript
|
|
802
|
+
client.getSuppressions('outbound', {
|
|
803
|
+
Count: 50,
|
|
804
|
+
Offset: 0,
|
|
805
|
+
EmailFilter: 'user@example.com'
|
|
806
|
+
}).then(result => {
|
|
807
|
+
console.log('Total suppressions:', result.Suppressions.length);
|
|
808
|
+
result.Suppressions.forEach(suppression => {
|
|
809
|
+
console.log('Email:', suppression.EmailAddress);
|
|
810
|
+
console.log('Reason:', suppression.SuppressionReason);
|
|
811
|
+
console.log('Created at:', suppression.CreatedAt);
|
|
812
|
+
});
|
|
813
|
+
});
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
### Create Suppressions
|
|
817
|
+
|
|
818
|
+
Manually suppress email addresses:
|
|
819
|
+
|
|
820
|
+
```javascript
|
|
821
|
+
client.createSuppressions('outbound', [
|
|
822
|
+
{ EmailAddress: 'user1@example.com' },
|
|
823
|
+
{ EmailAddress: 'user2@example.com' }
|
|
824
|
+
]).then(result => {
|
|
825
|
+
console.log('Suppressions created:', result.Suppressions.length);
|
|
826
|
+
});
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
### Delete Suppressions
|
|
830
|
+
|
|
831
|
+
Remove email addresses from suppression list:
|
|
832
|
+
|
|
833
|
+
```javascript
|
|
834
|
+
client.deleteSuppressions('outbound', [
|
|
835
|
+
{ EmailAddress: 'user1@example.com' },
|
|
836
|
+
{ EmailAddress: 'user2@example.com' }
|
|
837
|
+
]).then(result => {
|
|
838
|
+
console.log('Suppressions deleted:', result.Suppressions.length);
|
|
839
|
+
});
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
## Webhooks
|
|
843
|
+
|
|
844
|
+
### Get Webhooks
|
|
845
|
+
|
|
846
|
+
Retrieve configured webhooks:
|
|
847
|
+
|
|
848
|
+
```javascript
|
|
849
|
+
client.getWebhooks().then(webhooks => {
|
|
850
|
+
webhooks.Webhooks.forEach(webhook => {
|
|
851
|
+
console.log('Webhook ID:', webhook.ID);
|
|
852
|
+
console.log('URL:', webhook.Url);
|
|
853
|
+
console.log('Message stream:', webhook.MessageStream);
|
|
854
|
+
console.log('Triggers:', webhook.Triggers);
|
|
855
|
+
});
|
|
856
|
+
});
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
### Create Webhook
|
|
860
|
+
|
|
861
|
+
```javascript
|
|
862
|
+
client.createWebhook({
|
|
863
|
+
Url: 'https://example.com/webhooks/postmark',
|
|
864
|
+
MessageStream: 'outbound',
|
|
865
|
+
HttpAuth: {
|
|
866
|
+
Username: 'webhook_user',
|
|
867
|
+
Password: 'webhook_pass'
|
|
868
|
+
},
|
|
869
|
+
HttpHeaders: [
|
|
870
|
+
{ Name: 'X-Custom-Header', Value: 'value' }
|
|
871
|
+
],
|
|
872
|
+
Triggers: {
|
|
873
|
+
Open: { Enabled: true },
|
|
874
|
+
Click: { Enabled: true },
|
|
875
|
+
Delivery: { Enabled: true },
|
|
876
|
+
Bounce: { Enabled: true },
|
|
877
|
+
SpamComplaint: { Enabled: true }
|
|
878
|
+
}
|
|
879
|
+
}).then(webhook => {
|
|
880
|
+
console.log('Webhook created:', webhook.ID);
|
|
881
|
+
});
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
### Edit Webhook
|
|
885
|
+
|
|
886
|
+
```javascript
|
|
887
|
+
client.editWebhook(123456, {
|
|
888
|
+
Url: 'https://example.com/webhooks/postmark-updated',
|
|
889
|
+
Triggers: {
|
|
890
|
+
Open: { Enabled: true },
|
|
891
|
+
Click: { Enabled: true },
|
|
892
|
+
Delivery: { Enabled: false }
|
|
893
|
+
}
|
|
894
|
+
}).then(webhook => {
|
|
895
|
+
console.log('Webhook updated:', webhook.ID);
|
|
896
|
+
});
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
### Delete Webhook
|
|
900
|
+
|
|
901
|
+
```javascript
|
|
902
|
+
client.deleteWebhook(123456).then(response => {
|
|
903
|
+
console.log('Webhook deleted:', response.Message);
|
|
904
|
+
});
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
## Server Management (Account Client)
|
|
908
|
+
|
|
909
|
+
### Get Server
|
|
910
|
+
|
|
911
|
+
```javascript
|
|
912
|
+
const postmark = require('postmark');
|
|
913
|
+
const accountClient = new postmark.AccountClient(process.env.POSTMARK_ACCOUNT_TOKEN);
|
|
914
|
+
|
|
915
|
+
accountClient.getServer(123456).then(server => {
|
|
916
|
+
console.log('Server name:', server.Name);
|
|
917
|
+
console.log('Server ID:', server.ID);
|
|
918
|
+
console.log('Color:', server.Color);
|
|
919
|
+
});
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
### Create Server
|
|
923
|
+
|
|
924
|
+
```javascript
|
|
925
|
+
accountClient.createServer({
|
|
926
|
+
Name: 'Production Server',
|
|
927
|
+
Color: 'blue'
|
|
928
|
+
}).then(server => {
|
|
929
|
+
console.log('Server created:', server.ID);
|
|
930
|
+
console.log('Server token:', server.ApiTokens);
|
|
931
|
+
});
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
### Edit Server
|
|
935
|
+
|
|
936
|
+
```javascript
|
|
937
|
+
accountClient.editServer(123456, {
|
|
938
|
+
Name: 'Updated Server Name',
|
|
939
|
+
Color: 'green'
|
|
940
|
+
}).then(server => {
|
|
941
|
+
console.log('Server updated:', server.Name);
|
|
942
|
+
});
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
### List Servers
|
|
946
|
+
|
|
947
|
+
```javascript
|
|
948
|
+
accountClient.getServers({
|
|
949
|
+
Count: 50,
|
|
950
|
+
Offset: 0,
|
|
951
|
+
Name: 'Production'
|
|
952
|
+
}).then(result => {
|
|
953
|
+
console.log('Total servers:', result.TotalCount);
|
|
954
|
+
result.Servers.forEach(server => {
|
|
955
|
+
console.log('Server:', server.Name, '(ID:', server.ID + ')');
|
|
956
|
+
});
|
|
957
|
+
});
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
## Client Configuration
|
|
961
|
+
|
|
962
|
+
### Timeout Configuration
|
|
963
|
+
|
|
964
|
+
Set custom timeout for API requests:
|
|
965
|
+
|
|
966
|
+
```javascript
|
|
967
|
+
const postmark = require('postmark');
|
|
968
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
969
|
+
|
|
970
|
+
// Set timeout to 30 seconds (default is 30000ms)
|
|
971
|
+
client.setClientOptions({ timeout: 60000 });
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
### Custom Headers
|
|
975
|
+
|
|
976
|
+
Add default headers to all requests:
|
|
977
|
+
|
|
978
|
+
```javascript
|
|
979
|
+
client.setClientOptions({
|
|
980
|
+
headers: {
|
|
981
|
+
'X-Custom-Header': 'custom-value'
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
### Use Test Token
|
|
987
|
+
|
|
988
|
+
For testing without sending actual emails:
|
|
989
|
+
|
|
990
|
+
```javascript
|
|
991
|
+
const client = new postmark.ServerClient('POSTMARK_API_TEST');
|
|
992
|
+
|
|
993
|
+
// This will validate the API call but not actually send the email
|
|
994
|
+
client.sendEmail({
|
|
995
|
+
From: 'sender@example.com',
|
|
996
|
+
To: 'recipient@example.com',
|
|
997
|
+
Subject: 'Test email',
|
|
998
|
+
HtmlBody: '<p>This is a test.</p>'
|
|
999
|
+
});
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
## Error Handling
|
|
1003
|
+
|
|
1004
|
+
Always handle errors properly when making API calls:
|
|
1005
|
+
|
|
1006
|
+
```javascript
|
|
1007
|
+
const postmark = require('postmark');
|
|
1008
|
+
const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN);
|
|
1009
|
+
|
|
1010
|
+
async function sendEmailWithErrorHandling() {
|
|
1011
|
+
try {
|
|
1012
|
+
const response = await client.sendEmail({
|
|
1013
|
+
From: 'sender@example.com',
|
|
1014
|
+
To: 'recipient@example.com',
|
|
1015
|
+
Subject: 'Test',
|
|
1016
|
+
HtmlBody: '<p>Test email</p>'
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
console.log('Success:', response.MessageID);
|
|
1020
|
+
return response;
|
|
1021
|
+
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
// Handle specific error codes
|
|
1024
|
+
if (error.statusCode === 401) {
|
|
1025
|
+
console.error('Invalid API token');
|
|
1026
|
+
} else if (error.statusCode === 422) {
|
|
1027
|
+
console.error('Validation error:', error.message);
|
|
1028
|
+
} else if (error.statusCode === 429) {
|
|
1029
|
+
console.error('Rate limit exceeded');
|
|
1030
|
+
} else if (error.statusCode >= 500) {
|
|
1031
|
+
console.error('Server error:', error.message);
|
|
1032
|
+
} else {
|
|
1033
|
+
console.error('API error:', error.message);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
console.error('Error code:', error.code);
|
|
1037
|
+
console.error('Error details:', error.body);
|
|
1038
|
+
|
|
1039
|
+
throw error;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
sendEmailWithErrorHandling();
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
### Common Error Codes
|
|
1047
|
+
|
|
1048
|
+
| Status Code | Error Type | Description |
|
|
1049
|
+
|-------------|------------|-------------|
|
|
1050
|
+
| 401 | Unauthorized | Invalid or missing API token |
|
|
1051
|
+
| 403 | Forbidden | Sender signature not verified |
|
|
1052
|
+
| 422 | Unprocessable Entity | Validation error (invalid parameters) |
|
|
1053
|
+
| 429 | Too Many Requests | Rate limit exceeded |
|
|
1054
|
+
| 500 | Internal Server Error | Postmark server error |
|
|
1055
|
+
| 503 | Service Unavailable | Postmark temporarily unavailable |
|
|
1056
|
+
|
|
1057
|
+
### Batch Error Handling
|
|
1058
|
+
|
|
1059
|
+
When sending batch emails, check each response individually:
|
|
1060
|
+
|
|
1061
|
+
```javascript
|
|
1062
|
+
const responses = await client.sendEmailBatch([
|
|
1063
|
+
{ From: 'sender@example.com', To: 'user1@example.com', Subject: 'Test 1', HtmlBody: '<p>Test</p>' },
|
|
1064
|
+
{ From: 'sender@example.com', To: 'invalid-email', Subject: 'Test 2', HtmlBody: '<p>Test</p>' },
|
|
1065
|
+
{ From: 'sender@example.com', To: 'user3@example.com', Subject: 'Test 3', HtmlBody: '<p>Test</p>' }
|
|
1066
|
+
]);
|
|
1067
|
+
|
|
1068
|
+
responses.forEach((response, index) => {
|
|
1069
|
+
if (response.ErrorCode === 0) {
|
|
1070
|
+
console.log(`Email ${index + 1} sent successfully:`, response.MessageID);
|
|
1071
|
+
} else {
|
|
1072
|
+
console.error(`Email ${index + 1} failed:`, response.Message);
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
## TypeScript Support
|
|
1078
|
+
|
|
1079
|
+
The Postmark library includes full TypeScript definitions:
|
|
1080
|
+
|
|
1081
|
+
```typescript
|
|
1082
|
+
import * as postmark from 'postmark';
|
|
1083
|
+
import { ServerClient, Message, TemplatedMessage } from 'postmark';
|
|
1084
|
+
|
|
1085
|
+
const client: ServerClient = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN!);
|
|
1086
|
+
|
|
1087
|
+
interface EmailResponse {
|
|
1088
|
+
To: string;
|
|
1089
|
+
SubmittedAt: string;
|
|
1090
|
+
MessageID: string;
|
|
1091
|
+
ErrorCode: number;
|
|
1092
|
+
Message: string;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
async function sendTypedEmail(): Promise<EmailResponse> {
|
|
1096
|
+
const message: Message = new postmark.Models.Message(
|
|
1097
|
+
'sender@example.com',
|
|
1098
|
+
'Test email',
|
|
1099
|
+
'<p>HTML body</p>',
|
|
1100
|
+
'Text body',
|
|
1101
|
+
'recipient@example.com'
|
|
1102
|
+
);
|
|
1103
|
+
|
|
1104
|
+
const response = await client.sendEmail(message);
|
|
1105
|
+
return response;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
async function sendTemplateEmail(): Promise<EmailResponse> {
|
|
1109
|
+
const templateMessage: TemplatedMessage = {
|
|
1110
|
+
From: 'sender@example.com',
|
|
1111
|
+
To: 'recipient@example.com',
|
|
1112
|
+
TemplateId: 123456,
|
|
1113
|
+
TemplateModel: {
|
|
1114
|
+
name: 'John Doe',
|
|
1115
|
+
code: 'ABC123'
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
const response = await client.sendEmailWithTemplate(templateMessage);
|
|
1120
|
+
return response;
|
|
1121
|
+
}
|
|
1122
|
+
```
|
|
1123
|
+
|
|
1124
|
+
## ES6 Module Support
|
|
1125
|
+
|
|
1126
|
+
Use ES6 imports:
|
|
1127
|
+
|
|
1128
|
+
```javascript
|
|
1129
|
+
import * as postmark from 'postmark';
|
|
1130
|
+
|
|
1131
|
+
const serverToken = process.env.POSTMARK_SERVER_TOKEN;
|
|
1132
|
+
const client = new postmark.ServerClient(serverToken);
|
|
1133
|
+
|
|
1134
|
+
export async function sendWelcomeEmail(recipientEmail, userName) {
|
|
1135
|
+
return await client.sendEmailWithTemplate({
|
|
1136
|
+
From: 'welcome@example.com',
|
|
1137
|
+
To: recipientEmail,
|
|
1138
|
+
TemplateAlias: 'welcome-email',
|
|
1139
|
+
TemplateModel: {
|
|
1140
|
+
user_name: userName
|
|
1141
|
+
}
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
```
|
|
1145
|
+
|
|
1146
|
+
## Useful Links
|
|
1147
|
+
|
|
1148
|
+
- **Official Documentation:** https://postmarkapp.com/developer
|
|
1149
|
+
- **API Reference:** https://postmarkapp.com/developer/api/overview
|
|
1150
|
+
- **Node.js Library Docs:** https://activecampaign.github.io/postmark.js/
|
|
1151
|
+
- **GitHub Repository:** https://github.com/ActiveCampaign/postmark.js
|
|
1152
|
+
- **NPM Package:** https://www.npmjs.com/package/postmark
|
|
1153
|
+
- **Email API:** https://postmarkapp.com/developer/api/email-api
|
|
1154
|
+
- **Templates API:** https://postmarkapp.com/developer/api/templates-api
|
|
1155
|
+
- **Webhooks:** https://postmarkapp.com/developer/webhooks/webhooks-overview
|
|
1156
|
+
- **Support:** https://postmarkapp.com/support
|
|
1157
|
+
|
|
1158
|
+
## Notes
|
|
1159
|
+
|
|
1160
|
+
- Always verify sender signatures or domains before sending emails
|
|
1161
|
+
- Use the test token `POSTMARK_API_TEST` for development
|
|
1162
|
+
- Batch requests can include up to 500 messages (50 MB max)
|
|
1163
|
+
- Open tracking requires HTML body
|
|
1164
|
+
- Link tracking works in both HTML and text bodies
|
|
1165
|
+
- Metadata is included in webhooks and API responses
|
|
1166
|
+
- Messages are stored for 45 days by default (configurable up to 365 days)
|
|
1167
|
+
- Rate limits apply based on your account plan
|
|
1168
|
+
- Always check individual responses in batch operations
|