Profiles·Public

postmark

semver>=2.0.0postconditions9functions9last verified2026-04-16coverage score82%

Postconditions — what we check

  • sendEmail · api-error
    error
    WhenAny HTTP or network failure: invalid API token (401 InvalidAPIKeyError), validation error (422 ApiInputError — invalid sender, missing fields), inactive recipients (422/406 InactiveRecipientsError), rate limit exceeded (429 RateLimitExceededError), server error (500 InternalServerError), service unavailable (503 ServiceUnavailablerError), or network/DNS failure.
    ThrowsInvalidAPIKeyError (401 — bad server token), ApiInputError (422 — validation failures), InactiveRecipientsError (422/406 — bounced recipients, extends ApiInputError), InvalidEmailRequestError (422/300 — malformed email request, extends ApiInputError), RateLimitExceededError (429 — too many requests), InternalServerError (500 — Postmark server error), ServiceUnavailablerError (503 — Postmark unavailable), UnknownError (other HTTP status codes). All extend PostmarkError with code and statusCode properties.
    Required handlingCaller MUST wrap client.sendEmail() in try-catch. Email delivery failures must be detected — users expect confirmation emails, receipts, and notifications to arrive. Unhandled rejection crashes the process. Minimum handling: try { await client.sendEmail({ From, To, Subject, TextBody }); } catch (error) { if (error instanceof Errors.InactiveRecipientsError) { // Handle bounced recipient } console.error('Email send failed:', error.message); throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][2]
  • sendEmailBatch · api-error
    error
    WhenAny HTTP or network failure: authentication, validation, rate limit, server error, or network failure. Partial batch failures may occur where some emails succeed and others fail within the response.
    ThrowsSame error hierarchy as sendEmail. InvalidAPIKeyError (401), ApiInputError (422), RateLimitExceededError (429), InternalServerError (500), ServiceUnavailablerError (503).
    Required handlingCaller MUST wrap client.sendEmailBatch() in try-catch. Batch email failures affect multiple recipients simultaneously. try { const results = await client.sendEmailBatch(messages); } catch (error) { console.error('Batch send failed:', error.message); throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3][4]
  • sendEmailWithTemplate · api-error
    error
    WhenAny HTTP or network failure: authentication, template not found, validation error (missing template model variables), rate limit, server error, or network failure.
    ThrowsSame error hierarchy as sendEmail. Additionally, ApiInputError (422) is thrown when TemplateId/TemplateAlias is invalid or required TemplateModel variables are missing.
    Required handlingCaller MUST wrap client.sendEmailWithTemplate() in try-catch. try { await client.sendEmailWithTemplate({ TemplateAlias: 'welcome', TemplateModel: { name: user.name }, From: 'hello@example.com', To: user.email, }); } catch (error) { console.error('Template email failed:', error.message); throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][4]
  • sendEmailBatchWithTemplates · api-error
    error
    WhenAny HTTP or network failure: authentication, template not found, validation error, rate limit, server error, or network failure.
    ThrowsSame error hierarchy as sendEmail and sendEmailWithTemplate.
    Required handlingCaller MUST wrap client.sendEmailBatchWithTemplates() in try-catch. try { const results = await client.sendEmailBatchWithTemplates(messages); } catch (error) { console.error('Batch template send failed:', error.message); throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6][4]
  • activateBounce · activate-bounce-no-try-catch
    error
    WhenactivateBounce() called in async context without surrounding try/catch. Throws PostmarkError subclasses on any HTTP or network failure including invalid bounce ID (ApiInputError), revoked token (InvalidAPIKeyError), or bounce not eligible for reactivation (CanActivate: false).
    ThrowsPostmarkError (InvalidAPIKeyError 401, ApiInputError 422, UnknownError)
    Required handlingCaller MUST wrap activateBounce() in try-catch: try { const result = await client.activateBounce(bounceId); // result.Bounce.CanActivate tells you if it worked } catch (error) { if (error instanceof Errors.InvalidAPIKeyError) { // Auth token invalid } console.error('Bounce activation failed:', error.message); }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[7][2]
  • createSuppressions · create-suppressions-no-try-catch
    error
    WhencreateSuppressions() called in async context without surrounding try/catch, OR called without checking per-item Status in the response. The API returns 200 OK with Status: "Failed" for individual addresses on validation or authorization failure — not just on HTTP 4xx/5xx errors.
    ThrowsPostmarkError (InvalidAPIKeyError 401, InactiveRecipientsError 406, RateLimitExceededError 429)
    Required handlingCaller MUST wrap createSuppressions() in try-catch AND check item statuses: try { const result = await client.createSuppressions('outbound', { Suppressions: [{ EmailAddress: email }] }); const failed = result.Suppressions.filter(s => s.Status === 'Failed'); if (failed.length > 0) { console.error('Failed to suppress:', failed.map(s => s.EmailAddress)); } } catch (error) { console.error('Suppression API failed:', error.message); }
    costmediumin prodsilent failureusers seelost datavisibilitysilent
    Sources[8][4]
  • deleteSuppressions · delete-suppressions-no-try-catch
    error
    WhendeleteSuppressions() called in async context without surrounding try/catch, OR called without checking per-item Status in the response. SpamComplaint suppressions always return Status: "Failed" with HTTP 200 OK — this is not an exception, it is a silent API-level constraint that callers must check.
    ThrowsPostmarkError (InvalidAPIKeyError 401, RateLimitExceededError 429, ServerError 5xx)
    Required handlingCaller MUST wrap deleteSuppressions() in try-catch AND check item statuses: try { const result = await client.deleteSuppressions('outbound', { Suppressions: [{ EmailAddress: email }] }); const failed = result.Suppressions.filter(s => s.Status === 'Failed'); if (failed.length > 0) { // SpamComplaint suppressions cannot be deleted console.warn('Could not remove suppressions:', failed); } } catch (error) { console.error('Delete suppressions failed:', error.message); }
    costmediumin prodsilent failureusers seelost datavisibilitysilent
    Sources[8][4]
  • createTemplate · create-template-no-try-catch
    error
    WhencreateTemplate() called in async context without surrounding try/catch. Throws ApiInputError (422) for invalid alias format, missing required fields, or 100-template server limit exceeded. Throws InvalidAPIKeyError (401) for bad server token. Throws RateLimitExceededError (429) under high load.
    ThrowsPostmarkError (ApiInputError 422, InvalidAPIKeyError 401, RateLimitExceededError 429)
    Required handlingCaller MUST wrap createTemplate() in try-catch: try { const template = await client.createTemplate({ Name: 'Welcome Email', Subject: 'Welcome to {{product_name}}', HtmlBody: '<p>Hello, {{name}}!</p>', TextBody: 'Hello, {{name}}!', Alias: 'welcome-v1', }); console.log('Template ID:', template.TemplateId); } catch (error) { console.error('Template creation failed:', error.message); // Check if 100-template limit exceeded }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9][4]
  • editTemplate · edit-template-no-try-catch
    error
    WheneditTemplate() called in async context without surrounding try/catch. Throws ApiInputError (422) when template ID or alias is not found on the server, or when the alias format is invalid. Throws InvalidAPIKeyError (401) for auth failures. Throws RateLimitExceededError (429) and InternalServerError (500) under API failure conditions.
    ThrowsPostmarkError (ApiInputError 422, InvalidAPIKeyError 401, RateLimitExceededError 429)
    Required handlingCaller MUST wrap editTemplate() in try-catch: try { const updated = await client.editTemplate('welcome-v1', { Subject: 'Welcome to {{company_name}}!', HtmlBody: '<p>Hi {{name}}, welcome aboard!</p>', }); console.log('Template updated:', updated.TemplateId); } catch (error) { if (error instanceof Errors.ApiInputError) { console.error('Template not found or validation failed:', error.message); } else { console.error('Template update failed:', error.message); } throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9][4]

Sources

Every postcondition cites at least one of these. Numbered to match the footnotes above.

  1. [1]postmarkapp.com/developer/apihttps://postmarkapp.com/developer/api/email-api
  2. [2]github.com/ActiveCampaign/postmark.jshttps://github.com/ActiveCampaign/postmark.js/blob/main/src/client/errors/Errors.ts
  3. [3]postmarkapp.com/developer/apihttps://postmarkapp.com/developer/api/email-api#send-batch-emails
  4. [4]github.com/ActiveCampaign/postmark.jshttps://github.com/ActiveCampaign/postmark.js/blob/main/src/client/ServerClient.ts
  5. [5]postmarkapp.com/developer/apihttps://postmarkapp.com/developer/api/templates-api#send-email-with-template
  6. [6]postmarkapp.com/developer/apihttps://postmarkapp.com/developer/api/templates-api#send-batch-with-templates
  7. [7]postmarkapp.com/developer/apihttps://postmarkapp.com/developer/api/bounce-api
  8. [8]postmarkapp.com/developer/apihttps://postmarkapp.com/developer/api/suppressions-api
  9. [9]postmarkapp.com/developer/apihttps://postmarkapp.com/developer/api/templates-api
Need a different package?
Request a profile