Skip to content
← Public packages

@kody/agent-mail

AgentMail inboxes for agents: create/list inboxes, messages, threads, and Svix webhook ingress.

src/reply-to-message.ts

91 lines · 2.8 KB · TypeScript
import {
	agentMailRequest,
	clean,
	encodePathSegment,
	requireConfirmOrDryRun,
} from './core.ts'

export type ReplyToMessageInput = {
	inboxId: string
	messageId: string
	to?: string | string[]
	cc?: string | string[]
	bcc?: string | string[]
	replyTo?: string | string[]
	replyAll?: boolean
	text?: string
	html?: string
	labels?: string[]
	headers?: Record<string, string>
	trackOpens?: boolean
	attachments?: Array<Record<string, unknown>>
	/** Preview the request without calling AgentMail. */
	dryRun?: boolean
	/** Required true for a live reply (unless dryRun). */
	confirm?: boolean
}

/**
 * Reply to an AgentMail message.
 * Requires confirm: true for a live POST, or dryRun: true to preview.
 * Uses POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply.
 *
 * @param input.inboxId - AgentMail inbox id (required)
 * @param input.messageId - Message id to reply to (required)
 * @param input.text - Plain text reply body
 * @param input.html - HTML reply body
 * @param input.replyAll - Reply to all original recipients when true
 * @param input.dryRun - Preview without sending
 * @param input.confirm - Must be true for a live reply
 * @returns Reply result or dry-run preview
 *
 * @example
 * import replyToMessage from 'kody:@kody/agent-mail/reply-to-message'
 * const preview = await replyToMessage({
 *   inboxId: 'inbox_123',
 *   messageId: 'msg_456',
 *   text: 'Thanks — noted.',
 *   dryRun: true,
 * })
 */
export default async function replyToMessage(input: ReplyToMessageInput) {
	const mode = requireConfirmOrDryRun(input, 'send a live reply')
	const inboxId = encodePathSegment(input.inboxId, 'inboxId')
	const messageId = encodePathSegment(input.messageId, 'messageId')
	const body: Record<string, unknown> = {}
	if (input.to !== undefined) body.to = input.to
	if (input.cc !== undefined) body.cc = input.cc
	if (input.bcc !== undefined) body.bcc = input.bcc
	if (input.replyTo !== undefined) body.reply_to = input.replyTo
	if (input.replyAll !== undefined) body.reply_all = Boolean(input.replyAll)
	if (input.text !== undefined) body.text = input.text
	if (input.html !== undefined) body.html = input.html
	if (Array.isArray(input.labels)) body.labels = input.labels
	if (input.headers && typeof input.headers === 'object') body.headers = input.headers
	if (input.trackOpens !== undefined) body.track_opens = Boolean(input.trackOpens)
	if (Array.isArray(input.attachments)) body.attachments = input.attachments

	const path = `/v0/inboxes/${inboxId}/messages/${messageId}/reply`
	if (mode === 'dryRun') {
		return {
			dryRun: true as const,
			inboxId: clean(input.inboxId),
			messageId: clean(input.messageId),
			path,
			body,
		}
	}

	const result = await agentMailRequest({
		method: 'POST',
		path,
		body,
		label: 'AgentMail reply to message',
	})
	return {
		dryRun: false as const,
		inboxId: clean(input.inboxId),
		messageId: clean(input.messageId),
		result,
	}
}