425 lines
14 KiB
TypeScript
425 lines
14 KiB
TypeScript
import type { ApiSettings, DeltaDeletedItem } from "../types";
|
|
import { apiFetch } from "./client";
|
|
|
|
export type MailSecurity = "plain" | "tls" | "starttls";
|
|
export type MailProfileScope = "system" | "tenant" | "user" | "group" | "campaign";
|
|
|
|
export type MailSmtpTestPayload = {
|
|
host?: string | null;
|
|
port?: number | null;
|
|
username?: string | null;
|
|
password?: string | null;
|
|
security?: MailSecurity;
|
|
timeout_seconds?: number;
|
|
};
|
|
|
|
export type MailImapTestPayload = MailSmtpTestPayload & {
|
|
sent_folder?: string | null;
|
|
};
|
|
|
|
export type MailTransportCredentialsPayload = {
|
|
username?: string | null;
|
|
password?: string | null;
|
|
};
|
|
|
|
export type MailServerProfileCredentialsPayload = {
|
|
smtp?: MailTransportCredentialsPayload;
|
|
imap?: MailTransportCredentialsPayload;
|
|
};
|
|
|
|
export type MailConnectionTestResponse = {
|
|
ok: boolean;
|
|
protocol: "smtp" | "imap";
|
|
host?: string | null;
|
|
port?: number | null;
|
|
security?: MailSecurity | string | null;
|
|
message: string;
|
|
details?: Record<string, unknown>;
|
|
};
|
|
|
|
export type MailImapFolderResponse = {
|
|
name: string;
|
|
flags?: string[];
|
|
message_count?: number | null;
|
|
unseen_count?: number | null;
|
|
};
|
|
|
|
export type MailImapFolderListResponse = {
|
|
ok: boolean;
|
|
protocol: "imap";
|
|
host?: string | null;
|
|
port?: number | null;
|
|
security?: MailSecurity | string | null;
|
|
message: string;
|
|
folders: MailImapFolderResponse[];
|
|
detected_sent_folder?: string | null;
|
|
details?: Record<string, unknown>;
|
|
};
|
|
|
|
|
|
export type MailMailboxAttachment = {
|
|
filename?: string | null;
|
|
content_type: string;
|
|
size_bytes: number;
|
|
};
|
|
|
|
export type MailMailboxMessageSummary = {
|
|
uid: string;
|
|
folder: string;
|
|
subject?: string | null;
|
|
from_header?: string | null;
|
|
to_header?: string | null;
|
|
cc_header?: string | null;
|
|
bcc_header?: string | null;
|
|
date?: string | null;
|
|
message_id?: string | null;
|
|
flags?: string[];
|
|
size_bytes?: number | null;
|
|
body_preview?: string | null;
|
|
attachment_count?: number;
|
|
};
|
|
|
|
export type MailMailboxMessageDetail = MailMailboxMessageSummary & {
|
|
body_text?: string | null;
|
|
body_html?: string | null;
|
|
headers?: Record<string, string>;
|
|
attachments?: MailMailboxAttachment[];
|
|
};
|
|
|
|
export type MailMailboxMessageListResponse = {
|
|
profile_id: string;
|
|
folder: string;
|
|
host?: string | null;
|
|
port?: number | null;
|
|
security?: MailSecurity | string | null;
|
|
total_count?: number;
|
|
offset?: number;
|
|
limit?: number;
|
|
cursor?: string | null;
|
|
next_cursor?: string | null;
|
|
cursor_stable?: boolean;
|
|
full?: boolean;
|
|
messages: MailMailboxMessageSummary[];
|
|
};
|
|
|
|
export type MailMailboxMessageResponse = {
|
|
profile_id: string;
|
|
folder: string;
|
|
host?: string | null;
|
|
port?: number | null;
|
|
security?: MailSecurity | string | null;
|
|
message: MailMailboxMessageDetail;
|
|
};
|
|
|
|
export type MailServerProfile = {
|
|
id: string;
|
|
tenant_id?: string | null;
|
|
scope_type: MailProfileScope;
|
|
scope_id?: string | null;
|
|
name: string;
|
|
slug: string;
|
|
description?: string | null;
|
|
is_active: boolean;
|
|
smtp: MailSmtpTestPayload;
|
|
imap?: MailImapTestPayload | null;
|
|
credentials?: MailServerProfileCredentialsPayload | null;
|
|
smtp_password_configured: boolean;
|
|
imap_password_configured: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
export type MailServerProfileListResponse = { profiles: MailServerProfile[] };
|
|
|
|
export type MailSettingsDeltaResponse = {
|
|
profiles: MailServerProfile[];
|
|
policy?: MailProfilePolicyResponse | null;
|
|
changed_sections?: string[];
|
|
deleted: DeltaDeletedItem[];
|
|
watermark?: string | null;
|
|
has_more: boolean;
|
|
full: boolean;
|
|
};
|
|
|
|
export const mailProfilePatternKeys = [
|
|
"smtp_hosts",
|
|
"imap_hosts",
|
|
"envelope_senders",
|
|
"from_headers",
|
|
"recipient_domains"
|
|
] as const;
|
|
|
|
export type MailProfilePatternKey = typeof mailProfilePatternKeys[number];
|
|
export type MailProfilePatternRules = Partial<Record<MailProfilePatternKey, string[]>>;
|
|
|
|
export const mailProfilePolicyLimitKeys = [
|
|
"allowed_profile_ids",
|
|
"allow_user_profiles",
|
|
"allow_group_profiles",
|
|
"allow_campaign_profiles",
|
|
"smtp_credentials.inherit",
|
|
"imap_credentials.inherit",
|
|
"whitelist.smtp_hosts",
|
|
"whitelist.imap_hosts",
|
|
"whitelist.envelope_senders",
|
|
"whitelist.from_headers",
|
|
"whitelist.recipient_domains",
|
|
"blacklist.smtp_hosts",
|
|
"blacklist.imap_hosts",
|
|
"blacklist.envelope_senders",
|
|
"blacklist.from_headers",
|
|
"blacklist.recipient_domains"
|
|
] as const;
|
|
|
|
export type MailProfilePolicyLimitKey = typeof mailProfilePolicyLimitKeys[number];
|
|
export type MailProfilePolicyLimitPermissions = Partial<Record<MailProfilePolicyLimitKey, boolean>>;
|
|
|
|
export type MailCredentialPolicy = {
|
|
inherit?: boolean | null;
|
|
};
|
|
|
|
export type MailProfilePolicy = {
|
|
allowed_profile_ids?: string[] | null;
|
|
allow_user_profiles?: boolean | null;
|
|
allow_group_profiles?: boolean | null;
|
|
allow_campaign_profiles?: boolean | null;
|
|
smtp_credentials?: MailCredentialPolicy | null;
|
|
imap_credentials?: MailCredentialPolicy | null;
|
|
whitelist?: MailProfilePatternRules | null;
|
|
blacklist?: MailProfilePatternRules | null;
|
|
allow_lower_level_limits?: MailProfilePolicyLimitPermissions | null;
|
|
};
|
|
|
|
export type PolicySourceStep = {
|
|
scope_type: string;
|
|
scope_id?: string | null;
|
|
label: string;
|
|
applied_fields?: string[];
|
|
policy?: MailProfilePolicy | null;
|
|
};
|
|
|
|
export type MailProfilePolicyResponse = {
|
|
scope_type: MailProfileScope;
|
|
scope_id?: string | null;
|
|
policy: MailProfilePolicy;
|
|
effective_policy?: MailProfilePolicy | null;
|
|
parent_policy?: MailProfilePolicy | null;
|
|
effective_policy_sources?: PolicySourceStep[];
|
|
parent_policy_sources?: PolicySourceStep[];
|
|
};
|
|
|
|
export type MailServerProfilePayload = {
|
|
name: string;
|
|
slug?: string | null;
|
|
description?: string | null;
|
|
is_active?: boolean;
|
|
scope_type?: MailProfileScope;
|
|
scope_id?: string | null;
|
|
smtp: MailSmtpTestPayload;
|
|
imap?: MailImapTestPayload | null;
|
|
credentials?: MailServerProfileCredentialsPayload | null;
|
|
};
|
|
|
|
export async function listMailServerProfiles(settings: ApiSettings, includeInactive = false, campaignId?: string): Promise<MailServerProfile[]> {
|
|
const params = new URLSearchParams();
|
|
if (includeInactive) params.set("include_inactive", "true");
|
|
if (campaignId) params.set("campaign_id", campaignId);
|
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
const response = await apiFetch<MailServerProfileListResponse>(settings, `/api/v1/mail/profiles${suffix}`);
|
|
return response.profiles ?? [];
|
|
}
|
|
|
|
export async function fetchMailSettingsDelta(
|
|
settings: ApiSettings,
|
|
params: {
|
|
scope_type?: MailProfileScope;
|
|
scope_id?: string | null;
|
|
include_inactive?: boolean;
|
|
campaign_id?: string | null;
|
|
since?: string | null;
|
|
limit?: number;
|
|
} = {}
|
|
): Promise<MailSettingsDeltaResponse> {
|
|
const search = new URLSearchParams();
|
|
if (params.scope_type) search.set("scope_type", params.scope_type);
|
|
if (params.scope_id) search.set("scope_id", params.scope_id);
|
|
if (params.include_inactive) search.set("include_inactive", "true");
|
|
if (params.campaign_id) search.set("campaign_id", params.campaign_id);
|
|
if (params.since) search.set("since", params.since);
|
|
if (params.limit) search.set("limit", String(params.limit));
|
|
const suffix = search.toString() ? `?${search.toString()}` : "";
|
|
return apiFetch<MailSettingsDeltaResponse>(settings, `/api/v1/mail/settings/delta${suffix}`);
|
|
}
|
|
|
|
export async function createMailServerProfile(settings: ApiSettings, payload: MailServerProfilePayload): Promise<MailServerProfile> {
|
|
return apiFetch<MailServerProfile>(settings, "/api/v1/mail/profiles", {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export type MailServerProfileUpdatePayload = Partial<MailServerProfilePayload> & { clear_imap?: boolean };
|
|
|
|
export async function updateMailServerProfile(settings: ApiSettings, profileId: string, payload: MailServerProfileUpdatePayload): Promise<MailServerProfile> {
|
|
return apiFetch<MailServerProfile>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function deactivateMailServerProfile(settings: ApiSettings, profileId: string): Promise<MailServerProfile> {
|
|
return apiFetch<MailServerProfile>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}`, { method: "DELETE" });
|
|
}
|
|
|
|
export async function getMailProfilePolicy(
|
|
settings: ApiSettings,
|
|
scopeType: MailProfileScope,
|
|
scopeId?: string | null,
|
|
campaignId?: string | null
|
|
): Promise<MailProfilePolicyResponse> {
|
|
const params = new URLSearchParams();
|
|
if (scopeId) params.set("scope_id", scopeId);
|
|
if (campaignId) params.set("campaign_id", campaignId);
|
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
return apiFetch<MailProfilePolicyResponse>(settings, `/api/v1/mail/policies/${encodeURIComponent(scopeType)}${suffix}`);
|
|
}
|
|
|
|
export async function updateMailProfilePolicy(
|
|
settings: ApiSettings,
|
|
scopeType: MailProfileScope,
|
|
policy: MailProfilePolicy,
|
|
scopeId?: string | null
|
|
): Promise<MailProfilePolicyResponse> {
|
|
const params = new URLSearchParams();
|
|
if (scopeId) params.set("scope_id", scopeId);
|
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
return apiFetch<MailProfilePolicyResponse>(settings, `/api/v1/mail/policies/${encodeURIComponent(scopeType)}${suffix}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify({ policy })
|
|
});
|
|
}
|
|
|
|
export async function testMailProfileSmtp(settings: ApiSettings, profileId: string): Promise<MailConnectionTestResponse> {
|
|
return apiFetch<MailConnectionTestResponse>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}/test-smtp`, { method: "POST" });
|
|
}
|
|
|
|
export async function testMailProfileImap(settings: ApiSettings, profileId: string): Promise<MailConnectionTestResponse> {
|
|
return apiFetch<MailConnectionTestResponse>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}/test-imap`, { method: "POST" });
|
|
}
|
|
|
|
export async function listMailProfileImapFolders(settings: ApiSettings, profileId: string): Promise<MailImapFolderListResponse> {
|
|
return apiFetch<MailImapFolderListResponse>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}/list-imap-folders`, { method: "POST" });
|
|
}
|
|
|
|
export async function listMailboxFolders(settings: ApiSettings, profileId: string): Promise<MailImapFolderListResponse> {
|
|
return apiFetch<MailImapFolderListResponse>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}/mailbox/folders`);
|
|
}
|
|
|
|
export async function listMailboxMessages(
|
|
settings: ApiSettings,
|
|
profileId: string,
|
|
folder = "INBOX",
|
|
limit = 50,
|
|
offset = 0,
|
|
cursor?: string | null
|
|
): Promise<MailMailboxMessageListResponse> {
|
|
const params = new URLSearchParams({ folder, limit: String(limit), offset: String(offset) });
|
|
if (cursor) params.set("cursor", cursor);
|
|
return apiFetch<MailMailboxMessageListResponse>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}/mailbox/messages?${params.toString()}`);
|
|
}
|
|
|
|
export async function getMailboxMessage(
|
|
settings: ApiSettings,
|
|
profileId: string,
|
|
folder: string,
|
|
uid: string
|
|
): Promise<MailMailboxMessageResponse> {
|
|
const params = new URLSearchParams({ folder });
|
|
return apiFetch<MailMailboxMessageResponse>(settings, `/api/v1/mail/profiles/${encodeURIComponent(profileId)}/mailbox/messages/${encodeURIComponent(uid)}?${params.toString()}`);
|
|
}
|
|
|
|
export async function testSmtpSettings(
|
|
settings: ApiSettings,
|
|
payload: MailSmtpTestPayload
|
|
): Promise<MailConnectionTestResponse> {
|
|
return apiFetch<MailConnectionTestResponse>(settings, "/api/v1/mail/test-smtp", {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function testImapSettings(
|
|
settings: ApiSettings,
|
|
payload: MailImapTestPayload
|
|
): Promise<MailConnectionTestResponse> {
|
|
return apiFetch<MailConnectionTestResponse>(settings, "/api/v1/mail/test-imap", {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function listImapFolders(
|
|
settings: ApiSettings,
|
|
payload: MailImapTestPayload
|
|
): Promise<MailImapFolderListResponse> {
|
|
return apiFetch<MailImapFolderListResponse>(settings, "/api/v1/mail/list-imap-folders", {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export type MockMailboxMessage = {
|
|
id: string;
|
|
kind: "smtp" | "imap_append" | string;
|
|
created_at: string;
|
|
envelope_from?: string | null;
|
|
envelope_recipients?: string[];
|
|
subject?: string | null;
|
|
from_header?: string | null;
|
|
to_header?: string | null;
|
|
cc_header?: string | null;
|
|
bcc_header?: string | null;
|
|
message_id?: string | null;
|
|
size_bytes?: number;
|
|
body_preview?: string | null;
|
|
attachment_count?: number;
|
|
folder?: string | null;
|
|
raw_eml?: string | null;
|
|
headers?: Record<string, string>;
|
|
attachments?: Array<{ filename?: string | null; content_type?: string | null; size_bytes?: number }>;
|
|
};
|
|
|
|
export type MockMailboxListResponse = {
|
|
messages: MockMailboxMessage[];
|
|
};
|
|
|
|
export type MockMailboxMessageResponse = {
|
|
message: MockMailboxMessage;
|
|
};
|
|
|
|
export type MockMailboxFailureConfig = {
|
|
fail_next_smtp?: boolean | null;
|
|
fail_next_imap?: boolean | null;
|
|
smtp_reject_recipients_containing?: string | null;
|
|
};
|
|
|
|
export async function listMockMailboxMessages(settings: ApiSettings, kind?: string): Promise<MockMailboxListResponse> {
|
|
const suffix = kind ? `?kind=${encodeURIComponent(kind)}` : "";
|
|
return apiFetch<MockMailboxListResponse>(settings, `/api/v1/dev/mailbox/messages${suffix}`);
|
|
}
|
|
|
|
export async function getMockMailboxMessage(settings: ApiSettings, id: string): Promise<MockMailboxMessageResponse> {
|
|
return apiFetch<MockMailboxMessageResponse>(settings, `/api/v1/dev/mailbox/messages/${encodeURIComponent(id)}`);
|
|
}
|
|
|
|
export async function clearMockMailboxMessages(settings: ApiSettings): Promise<{ deleted_count: number }> {
|
|
return apiFetch<{ deleted_count: number }>(settings, "/api/v1/dev/mailbox/messages", { method: "DELETE" });
|
|
}
|
|
|
|
export async function updateMockMailboxFailures(settings: ApiSettings, payload: MockMailboxFailureConfig): Promise<{ config: MockMailboxFailureConfig }> {
|
|
return apiFetch<{ config: MockMailboxFailureConfig }>(settings, "/api/v1/dev/mailbox/failures", {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|