fix(messages): dynamic addresses, branding accent, compose/sync, per-identity SMTP

Addresses dev-test feedback:
- Sidebar + reading-pane addresses (rechnungen@ / hello@ / no-reply@) are now
  read from the mail config via GET /admin/email/identities, not hardcoded.
- Highlight/selection now uses the branding accent (bg-accent-soft /
  text-on-accent-soft / accent-dark) instead of hardcoded blue, so it follows
  the admin's CI colour like the sidebar.
- Header gains "New message" (compose) and "Sync" (poll mailboxes now) buttons.
- Composer modal enlarged (920px, taller editable body).
- Customer mailbox (hello@) now has BOTH incoming (IMAP) and outgoing (SMTP)
  settings — migration 156 adds smtp_* + from_* to mail_accounts;
  emailProcessor.sendRawEmail takes an accountKey and sends via that mailbox's
  SMTP identity (falls back to the global from). Manual/reply sends from the
  Messages UI use the 'customers' identity, so replies come from hello@.

Frontend build + migration boot (156) verified.
This commit is contained in:
Luca
2026-07-07 11:58:41 +02:00
parent 976d52280e
commit f9c2b4ed75
7 changed files with 249 additions and 38 deletions
+22 -1
View File
@@ -160,9 +160,24 @@ export interface MailAccount {
imap_user?: string | null;
imap_pass?: string;
imap_folder?: string;
// Outgoing (SMTP) identity — replies from this mailbox send from here.
smtp_host?: string | null;
smtp_port?: number;
smtp_secure?: boolean;
smtp_user?: string | null;
smtp_pass?: string;
from_email?: string | null;
from_name?: string | null;
enabled?: boolean;
}
/** Resolved sender/mailbox addresses for the Messages sidebar. */
export interface MailIdentities {
automated: string | null;
accounting: string | null;
customers: string | null;
}
export const emailService = {
// Get email configuration
async getConfig(): Promise<EmailConfig> {
@@ -264,10 +279,16 @@ export const emailService = {
},
/** Send a human-composed (edited) email — reply or document message. */
async sendMessage(payload: { to: string; cc?: string; subject: string; html: string; replyToReceivedId?: number }): Promise<void> {
async sendMessage(payload: { to: string; cc?: string; subject: string; html: string; replyToReceivedId?: number; accountKey?: string }): Promise<void> {
await api.post('/admin/email/send', payload);
},
/** Resolved sender/mailbox addresses for the Messages sidebar. */
async getIdentities(): Promise<MailIdentities> {
const response = await api.get<MailIdentities>('/admin/email/identities');
return response.data;
},
// Get all email templates
async getTemplates(): Promise<EmailTemplate[]> {
const response = await api.get<EmailTemplate[]>('/admin/email/templates');