- Add PlatformEmailAddress model for managing platform-level email addresses - Add TicketEmailAddress model for tenant-level email addresses - Create MailServerService for IMAP integration with mail.talova.net - Implement PlatformEmailReceiver for processing incoming platform emails - Add email autoconfiguration for Mozilla, Microsoft, and Apple clients - Add configurable email polling interval in platform settings - Add "Check Emails" button on support page for manual refresh - Add ticket counts to status tabs on support page - Add platform email addresses management page - Add Privacy Policy and Terms of Service pages - Add robots.txt for SEO - Restrict email addresses to smoothschedule.com domain only 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
251 lines
6.5 KiB
TypeScript
251 lines
6.5 KiB
TypeScript
/**
|
|
* API client for Platform Email Addresses
|
|
* These are email addresses managed directly on the mail.talova.net server
|
|
*/
|
|
|
|
import apiClient from './client';
|
|
|
|
export interface PlatformEmailAddress {
|
|
id: number;
|
|
display_name: string;
|
|
sender_name: string;
|
|
effective_sender_name: string;
|
|
local_part: string;
|
|
domain: string;
|
|
email_address: string;
|
|
color: string;
|
|
is_active: boolean;
|
|
is_default: boolean;
|
|
mail_server_synced: boolean;
|
|
last_sync_error?: string;
|
|
last_synced_at?: string;
|
|
last_check_at?: string;
|
|
emails_processed_count: number;
|
|
created_at: string;
|
|
updated_at: string;
|
|
imap_settings?: {
|
|
host: string;
|
|
port: number;
|
|
use_ssl: boolean;
|
|
username: string;
|
|
folder: string;
|
|
};
|
|
smtp_settings?: {
|
|
host: string;
|
|
port: number;
|
|
use_tls: boolean;
|
|
use_ssl: boolean;
|
|
username: string;
|
|
};
|
|
}
|
|
|
|
export interface AssignedUser {
|
|
id: number;
|
|
email: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
full_name: string;
|
|
}
|
|
|
|
export interface AssignableUser extends AssignedUser {
|
|
role: string;
|
|
}
|
|
|
|
export interface PlatformEmailAddressListItem {
|
|
id: number;
|
|
display_name: string;
|
|
sender_name: string;
|
|
effective_sender_name: string;
|
|
local_part: string;
|
|
domain: string;
|
|
email_address: string;
|
|
color: string;
|
|
assigned_user?: AssignedUser | null;
|
|
is_active: boolean;
|
|
is_default: boolean;
|
|
mail_server_synced: boolean;
|
|
last_check_at?: string;
|
|
emails_processed_count: number;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface PlatformEmailAddressCreate {
|
|
display_name: string;
|
|
sender_name?: string;
|
|
assigned_user_id?: number | null;
|
|
local_part: string;
|
|
domain: string;
|
|
color: string;
|
|
password: string;
|
|
is_active: boolean;
|
|
is_default: boolean;
|
|
}
|
|
|
|
export interface PlatformEmailAddressUpdate {
|
|
display_name?: string;
|
|
sender_name?: string;
|
|
assigned_user_id?: number | null;
|
|
color?: string;
|
|
password?: string;
|
|
is_active?: boolean;
|
|
is_default?: boolean;
|
|
}
|
|
|
|
export interface EmailDomain {
|
|
value: string;
|
|
label: string;
|
|
}
|
|
|
|
export interface TestConnectionResponse {
|
|
success: boolean;
|
|
message: string;
|
|
}
|
|
|
|
export interface SyncResponse {
|
|
success: boolean;
|
|
message: string;
|
|
mail_server_synced?: boolean;
|
|
last_synced_at?: string;
|
|
last_sync_error?: string;
|
|
}
|
|
|
|
export interface MailServerAccountsResponse {
|
|
success: boolean;
|
|
accounts: { email: string; raw_line: string }[];
|
|
count: number;
|
|
}
|
|
|
|
export interface ImportFromMailServerResponse {
|
|
success: boolean;
|
|
imported: { id: number; email: string; display_name: string }[];
|
|
imported_count: number;
|
|
skipped: { email: string; reason: string }[];
|
|
skipped_count: number;
|
|
message: string;
|
|
}
|
|
|
|
/**
|
|
* Get all platform email addresses
|
|
*/
|
|
export const getPlatformEmailAddresses = async (): Promise<PlatformEmailAddressListItem[]> => {
|
|
const response = await apiClient.get('/platform/email-addresses/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get a specific platform email address by ID
|
|
*/
|
|
export const getPlatformEmailAddress = async (id: number): Promise<PlatformEmailAddress> => {
|
|
const response = await apiClient.get(`/platform/email-addresses/${id}/`);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Create a new platform email address
|
|
*/
|
|
export const createPlatformEmailAddress = async (
|
|
data: PlatformEmailAddressCreate
|
|
): Promise<PlatformEmailAddress> => {
|
|
const response = await apiClient.post('/platform/email-addresses/', data);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Update an existing platform email address
|
|
*/
|
|
export const updatePlatformEmailAddress = async (
|
|
id: number,
|
|
data: PlatformEmailAddressUpdate
|
|
): Promise<PlatformEmailAddress> => {
|
|
const response = await apiClient.patch(`/platform/email-addresses/${id}/`, data);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Delete a platform email address (also removes from mail server)
|
|
*/
|
|
export const deletePlatformEmailAddress = async (id: number): Promise<void> => {
|
|
await apiClient.delete(`/platform/email-addresses/${id}/`);
|
|
};
|
|
|
|
/**
|
|
* Remove email address from database only (keeps mail server account)
|
|
*/
|
|
export const removeLocalPlatformEmailAddress = async (id: number): Promise<{ success: boolean; message: string }> => {
|
|
const response = await apiClient.post(`/platform/email-addresses/${id}/remove_local/`);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Sync email address to mail server
|
|
*/
|
|
export const syncPlatformEmailAddress = async (id: number): Promise<SyncResponse> => {
|
|
const response = await apiClient.post(`/platform/email-addresses/${id}/sync/`);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Test IMAP connection for a platform email address
|
|
*/
|
|
export const testImapConnection = async (id: number): Promise<TestConnectionResponse> => {
|
|
const response = await apiClient.post(`/platform/email-addresses/${id}/test_imap/`);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Test SMTP connection for a platform email address
|
|
*/
|
|
export const testSmtpConnection = async (id: number): Promise<TestConnectionResponse> => {
|
|
const response = await apiClient.post(`/platform/email-addresses/${id}/test_smtp/`);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Set a platform email address as the default
|
|
*/
|
|
export const setAsDefault = async (id: number): Promise<{ success: boolean; message: string }> => {
|
|
const response = await apiClient.post(`/platform/email-addresses/${id}/set_as_default/`);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Test SSH connection to the mail server
|
|
*/
|
|
export const testMailServerConnection = async (): Promise<TestConnectionResponse> => {
|
|
const response = await apiClient.post('/platform/email-addresses/test_mail_server/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get all email accounts from the mail server
|
|
*/
|
|
export const getMailServerAccounts = async (): Promise<MailServerAccountsResponse> => {
|
|
const response = await apiClient.get('/platform/email-addresses/mail_server_accounts/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get available email domains
|
|
*/
|
|
export const getAvailableDomains = async (): Promise<{ domains: EmailDomain[] }> => {
|
|
const response = await apiClient.get('/platform/email-addresses/available_domains/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get assignable users (platform users who can be assigned to email addresses)
|
|
*/
|
|
export const getAssignableUsers = async (): Promise<{ users: AssignableUser[] }> => {
|
|
const response = await apiClient.get('/platform/email-addresses/assignable_users/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Import email addresses from the mail server
|
|
*/
|
|
export const importFromMailServer = async (): Promise<ImportFromMailServerResponse> => {
|
|
const response = await apiClient.post('/platform/email-addresses/import_from_mail_server/');
|
|
return response.data;
|
|
};
|