Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/postmark

src/messages.ts

130 lines · 3.8 KB · TypeScript
import {
	messageSummary,
	pagingQuery,
	postmarkRequest,
	type PostmarkAuthOptions,
	type PostmarkObject,
} from './core.ts'

function auth(input: PostmarkAuthOptions) {
	return { account: input.account, secretName: input.secretName }
}

export type SearchOutboundInput = PostmarkAuthOptions & {
	count?: number
	offset?: number
	recipient?: string
	fromEmail?: string
	tag?: string
	status?: 'queued' | 'sent' | 'processed'
	fromDate?: string
	toDate?: string
	subject?: string
	messageStream?: string
	metadata?: Record<string, string>
}

function outboundQuery(input: SearchOutboundInput) {
	const paging = pagingQuery(input)
	const query: Record<string, string | number | undefined> = {
		...paging,
		recipient: input.recipient,
		fromemail: input.fromEmail,
		tag: input.tag,
		status: input.status,
		fromdate: input.fromDate,
		todate: input.toDate,
		subject: input.subject,
		messagestream: input.messageStream,
	}
	if (input.metadata) {
		const entries = Object.entries(input.metadata).filter(([, value]) => value != null && value !== '')
		if (entries.length > 1) {
			throw new Error('Postmark outbound search accepts one metadata field at a time.')
		}
		for (const [key, value] of entries) {
			query['metadata_' + key] = value
		}
	}
	return query
}

/** GET /messages/outbound — search sent mail on the Server API token. */
export async function searchOutboundMessages(input: SearchOutboundInput = {}) {
	const body = (await postmarkRequest({
		path: '/messages/outbound',
		tokenKind: 'server',
		query: outboundQuery(input),
		...auth(input),
	})) as { TotalCount?: number; Messages?: PostmarkObject[] }
	const messages = Array.isArray(body.Messages) ? body.Messages : []
	return {
		totalCount: body.TotalCount ?? messages.length,
		messages: messages.map((message) => messageSummary(message)).filter(Boolean),
	}
}

/** GET /messages/outbound/{id}/details — one outbound message. */
export async function getOutboundMessage(input: PostmarkAuthOptions & { messageId: string }) {
	if (!input.messageId) throw new Error('getOutboundMessage: messageId is required')
	return await postmarkRequest({
		path: '/messages/outbound/' + encodeURIComponent(input.messageId) + '/details',
		tokenKind: 'server',
		...auth(input),
	})
}

export type SearchInboundInput = PostmarkAuthOptions & {
	count?: number
	offset?: number
	recipient?: string
	fromEmail?: string
	tag?: string
	subject?: string
	mailboxHash?: string
	status?: 'blocked' | 'processed' | 'queued' | 'failed' | 'scheduled'
	fromDate?: string
	toDate?: string
}

/** GET /messages/inbound — search inbound mail on the Server API token. */
export async function searchInboundMessages(input: SearchInboundInput = {}) {
	const paging = pagingQuery(input)
	const body = (await postmarkRequest({
		path: '/messages/inbound',
		tokenKind: 'server',
		query: {
			...paging,
			recipient: input.recipient,
			fromemail: input.fromEmail,
			tag: input.tag,
			subject: input.subject,
			mailboxhash: input.mailboxHash,
			status: input.status,
			fromdate: input.fromDate,
			todate: input.toDate,
		},
		...auth(input),
	})) as { TotalCount?: number; InboundMessages?: PostmarkObject[]; Messages?: PostmarkObject[] }
	const messages = Array.isArray(body.InboundMessages)
		? body.InboundMessages
		: Array.isArray(body.Messages)
			? body.Messages
			: []
	return {
		totalCount: body.TotalCount ?? messages.length,
		messages: messages.map((message) => messageSummary(message)).filter(Boolean),
	}
}

/** GET /messages/inbound/{id}/details — one inbound message. */
export async function getInboundMessage(input: PostmarkAuthOptions & { messageId: string }) {
	if (!input.messageId) throw new Error('getInboundMessage: messageId is required')
	return await postmarkRequest({
		path: '/messages/inbound/' + encodeURIComponent(input.messageId) + '/details',
		tokenKind: 'server',
		...auth(input),
	})
}

export default searchOutboundMessages