update
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
"@api.global/typedserver": "^3.0.74",
|
"@api.global/typedserver": "^3.0.74",
|
||||||
"@api.global/typedsocket": "^3.0.0",
|
"@api.global/typedsocket": "^3.0.0",
|
||||||
"@apiclient.xyz/cloudflare": "^6.4.1",
|
"@apiclient.xyz/cloudflare": "^6.4.1",
|
||||||
"@design.estate/dees-catalog": "^1.10.2",
|
"@design.estate/dees-catalog": "^1.10.7",
|
||||||
"@design.estate/dees-element": "^2.0.45",
|
"@design.estate/dees-element": "^2.0.45",
|
||||||
"@push.rocks/projectinfo": "^5.0.1",
|
"@push.rocks/projectinfo": "^5.0.1",
|
||||||
"@push.rocks/qenv": "^6.1.0",
|
"@push.rocks/qenv": "^6.1.0",
|
||||||
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -24,8 +24,8 @@ importers:
|
|||||||
specifier: ^6.4.1
|
specifier: ^6.4.1
|
||||||
version: 6.4.1
|
version: 6.4.1
|
||||||
'@design.estate/dees-catalog':
|
'@design.estate/dees-catalog':
|
||||||
specifier: ^1.10.2
|
specifier: ^1.10.7
|
||||||
version: 1.10.2(@tiptap/pm@2.23.0)
|
version: 1.10.7(@tiptap/pm@2.23.0)
|
||||||
'@design.estate/dees-element':
|
'@design.estate/dees-element':
|
||||||
specifier: ^2.0.45
|
specifier: ^2.0.45
|
||||||
version: 2.0.45
|
version: 2.0.45
|
||||||
@@ -344,8 +344,8 @@ packages:
|
|||||||
'@dabh/diagnostics@2.0.3':
|
'@dabh/diagnostics@2.0.3':
|
||||||
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
||||||
|
|
||||||
'@design.estate/dees-catalog@1.10.2':
|
'@design.estate/dees-catalog@1.10.7':
|
||||||
resolution: {integrity: sha512-hLdXbRUWpyYspZFhmp/S/GtOnhMPfa03ruMOX3dhkzTKoVymp2WxSjUID0zQlv+Y/P1iNMnwIfhzGkJsInhCTQ==}
|
resolution: {integrity: sha512-q5ukOfTzVaOSocrNQIOCc4sugw3flPW3RzvCfEISmRh0ziq6oadRcPcTgg8cYTOVT58C/oIWZZgsAz22W3RyZQ==}
|
||||||
|
|
||||||
'@design.estate/dees-comms@1.0.27':
|
'@design.estate/dees-comms@1.0.27':
|
||||||
resolution: {integrity: sha512-GvzTUwkV442LD60T08iqSoqvhA02Mou5lFvvqBPc4yBUiU7cZISqBx+76xvMgMIEI9Dx9JfTl4/2nW8MoVAanw==}
|
resolution: {integrity: sha512-GvzTUwkV442LD60T08iqSoqvhA02Mou5lFvvqBPc4yBUiU7cZISqBx+76xvMgMIEI9Dx9JfTl4/2nW8MoVAanw==}
|
||||||
@@ -5500,7 +5500,7 @@ snapshots:
|
|||||||
enabled: 2.0.0
|
enabled: 2.0.0
|
||||||
kuler: 2.0.0
|
kuler: 2.0.0
|
||||||
|
|
||||||
'@design.estate/dees-catalog@1.10.2(@tiptap/pm@2.23.0)':
|
'@design.estate/dees-catalog@1.10.7(@tiptap/pm@2.23.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-domtools': 2.3.3
|
'@design.estate/dees-domtools': 2.3.3
|
||||||
'@design.estate/dees-element': 2.0.45
|
'@design.estate/dees-element': 2.0.45
|
||||||
|
@@ -5,7 +5,7 @@ import * as paths from './paths.js';
|
|||||||
|
|
||||||
// Import the email server and its configuration
|
// Import the email server and its configuration
|
||||||
import { UnifiedEmailServer, type IUnifiedEmailServerOptions } from './mail/routing/classes.unified.email.server.js';
|
import { UnifiedEmailServer, type IUnifiedEmailServerOptions } from './mail/routing/classes.unified.email.server.js';
|
||||||
import type { IEmailRoute } from './mail/routing/interfaces.js';
|
import type { IEmailRoute, IEmailDomainConfig } from './mail/routing/interfaces.js';
|
||||||
import { logger } from './logger.js';
|
import { logger } from './logger.js';
|
||||||
// Import the email configuration helpers directly from mail/delivery
|
// Import the email configuration helpers directly from mail/delivery
|
||||||
import { configureEmailStorage, configureEmailServer } from './mail/delivery/index.js';
|
import { configureEmailStorage, configureEmailServer } from './mail/delivery/index.js';
|
||||||
@@ -640,9 +640,28 @@ export class DcRouter {
|
|||||||
465: 10465 // SMTPS
|
465: 10465 // SMTPS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Transform domains if they are provided as strings
|
||||||
|
let transformedDomains = this.options.emailConfig.domains;
|
||||||
|
if (transformedDomains && transformedDomains.length > 0) {
|
||||||
|
// Check if domains are strings (for backward compatibility)
|
||||||
|
if (typeof transformedDomains[0] === 'string') {
|
||||||
|
transformedDomains = (transformedDomains as any).map((domain: string) => ({
|
||||||
|
domain,
|
||||||
|
dnsMode: 'external-dns' as const,
|
||||||
|
dkim: {
|
||||||
|
selector: 'default',
|
||||||
|
keySize: 2048,
|
||||||
|
rotateKeys: false,
|
||||||
|
rotationInterval: 90
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create config with mapped ports
|
// Create config with mapped ports
|
||||||
const emailConfig: IUnifiedEmailServerOptions = {
|
const emailConfig: IUnifiedEmailServerOptions = {
|
||||||
...this.options.emailConfig,
|
...this.options.emailConfig,
|
||||||
|
domains: transformedDomains,
|
||||||
ports: this.options.emailConfig.ports.map(port => portMapping[port] || port + 10000),
|
ports: this.options.emailConfig.ports.map(port => portMapping[port] || port + 10000),
|
||||||
hostname: 'localhost' // Listen on localhost for SmartProxy forwarding
|
hostname: 'localhost' // Listen on localhost for SmartProxy forwarding
|
||||||
};
|
};
|
||||||
|
@@ -158,7 +158,7 @@ export class UnifiedEmailServer extends EventEmitter {
|
|||||||
private dcRouter: DcRouter;
|
private dcRouter: DcRouter;
|
||||||
private options: IUnifiedEmailServerOptions;
|
private options: IUnifiedEmailServerOptions;
|
||||||
private emailRouter: EmailRouter;
|
private emailRouter: EmailRouter;
|
||||||
private domainRegistry: DomainRegistry;
|
public domainRegistry: DomainRegistry;
|
||||||
private servers: any[] = [];
|
private servers: any[] = [];
|
||||||
private stats: IServerStats;
|
private stats: IServerStats;
|
||||||
|
|
||||||
|
@@ -65,6 +65,7 @@ export class ConfigHandler {
|
|||||||
perHour: number;
|
perHour: number;
|
||||||
perDay: number;
|
perDay: number;
|
||||||
};
|
};
|
||||||
|
domains?: string[];
|
||||||
};
|
};
|
||||||
dns: {
|
dns: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
@@ -88,6 +89,17 @@ export class ConfigHandler {
|
|||||||
}> {
|
}> {
|
||||||
const dcRouter = this.opsServerRef.dcRouterRef;
|
const dcRouter = this.opsServerRef.dcRouterRef;
|
||||||
|
|
||||||
|
// Get email domains if email server is configured
|
||||||
|
let emailDomains: string[] = [];
|
||||||
|
if (dcRouter.emailServer && dcRouter.emailServer.domainRegistry) {
|
||||||
|
emailDomains = dcRouter.emailServer.domainRegistry.getAllDomains();
|
||||||
|
} else if (dcRouter.options.emailConfig?.domains) {
|
||||||
|
// Fallback: get domains from email config options
|
||||||
|
emailDomains = dcRouter.options.emailConfig.domains.map(d =>
|
||||||
|
typeof d === 'string' ? d : d.domain
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
email: {
|
email: {
|
||||||
enabled: !!dcRouter.emailServer,
|
enabled: !!dcRouter.emailServer,
|
||||||
@@ -98,6 +110,7 @@ export class ConfigHandler {
|
|||||||
perHour: 100,
|
perHour: 100,
|
||||||
perDay: 1000,
|
perDay: 1000,
|
||||||
},
|
},
|
||||||
|
domains: emailDomains,
|
||||||
},
|
},
|
||||||
dns: {
|
dns: {
|
||||||
enabled: !!dcRouter.dnsServer,
|
enabled: !!dcRouter.dnsServer,
|
||||||
|
@@ -50,9 +50,13 @@ export class OpsViewEmails extends DeesElement {
|
|||||||
@state()
|
@state()
|
||||||
private searchTerm = '';
|
private searchTerm = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private emailDomains: string[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.loadEmails();
|
this.loadEmails();
|
||||||
|
this.loadEmailDomains();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
@@ -436,6 +440,11 @@ export class OpsViewEmails extends DeesElement {
|
|||||||
private async openComposeModal(replyTo?: IEmail, replyAll = false, forward = false) {
|
private async openComposeModal(replyTo?: IEmail, replyAll = false, forward = false) {
|
||||||
const { DeesModal } = await import('@design.estate/dees-catalog');
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
||||||
|
|
||||||
|
// Ensure domains are loaded before opening modal
|
||||||
|
if (this.emailDomains.length === 0) {
|
||||||
|
await this.loadEmailDomains();
|
||||||
|
}
|
||||||
|
|
||||||
await DeesModal.createAndShow({
|
await DeesModal.createAndShow({
|
||||||
heading: forward ? 'Forward Email' : replyTo ? 'Reply to Email' : 'New Email',
|
heading: forward ? 'Forward Email' : replyTo ? 'Reply to Email' : 'New Email',
|
||||||
width: 'large',
|
width: 'large',
|
||||||
@@ -447,18 +456,27 @@ export class OpsViewEmails extends DeesElement {
|
|||||||
const modals = document.querySelectorAll('dees-modal');
|
const modals = document.querySelectorAll('dees-modal');
|
||||||
modals.forEach(m => (m as any).destroy?.());
|
modals.forEach(m => (m as any).destroy?.());
|
||||||
}}>
|
}}>
|
||||||
<dees-input-dropdown
|
<div style="display: flex; gap: 8px; align-items: flex-end;">
|
||||||
key="from"
|
<dees-input-text
|
||||||
label="From"
|
key="fromUsername"
|
||||||
.options=${[
|
label="From"
|
||||||
{ key: 'admin@dcrouter.local', value: 'Admin <admin@dcrouter.local>' },
|
placeholder="username"
|
||||||
{ key: 'noreply@dcrouter.local', value: 'No Reply <noreply@dcrouter.local>' },
|
.value=${'admin'}
|
||||||
{ key: 'support@dcrouter.local', value: 'Support <support@dcrouter.local>' },
|
required
|
||||||
{ key: 'alerts@dcrouter.local', value: 'Alerts <alerts@dcrouter.local>' }
|
style="flex: 1;"
|
||||||
]}
|
></dees-input-text>
|
||||||
.selectedKey=${'admin@dcrouter.local'}
|
<span style="padding-bottom: 12px; font-size: 18px; color: #666;">@</span>
|
||||||
required
|
<dees-input-dropdown
|
||||||
></dees-input-dropdown>
|
key="fromDomain"
|
||||||
|
label=" "
|
||||||
|
.options=${this.emailDomains.length > 0
|
||||||
|
? this.emailDomains.map(domain => ({ key: domain, value: domain }))
|
||||||
|
: [{ key: 'dcrouter.local', value: 'dcrouter.local' }]}
|
||||||
|
.selectedKey=${this.emailDomains[0] || 'dcrouter.local'}
|
||||||
|
required
|
||||||
|
style="flex: 1;"
|
||||||
|
></dees-input-dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
<dees-input-tags
|
<dees-input-tags
|
||||||
key="to"
|
key="to"
|
||||||
@@ -567,6 +585,25 @@ export class OpsViewEmails extends DeesElement {
|
|||||||
this.generateMockEmails();
|
this.generateMockEmails();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async loadEmailDomains() {
|
||||||
|
try {
|
||||||
|
// Fetch configuration from the server
|
||||||
|
await appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
|
||||||
|
const config = appstate.configStatePart.getState().config;
|
||||||
|
|
||||||
|
if (config?.email?.domains && Array.isArray(config.email.domains) && config.email.domains.length > 0) {
|
||||||
|
this.emailDomains = config.email.domains;
|
||||||
|
} else {
|
||||||
|
// Fallback to default domains if none configured
|
||||||
|
this.emailDomains = ['dcrouter.local'];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load email domains:', error);
|
||||||
|
// Fallback to default domain on error
|
||||||
|
this.emailDomains = ['dcrouter.local'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async refreshEmails() {
|
private async refreshEmails() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
await this.loadEmails();
|
await this.loadEmails();
|
||||||
@@ -579,9 +616,12 @@ export class OpsViewEmails extends DeesElement {
|
|||||||
console.log('Sending email:', formData);
|
console.log('Sending email:', formData);
|
||||||
|
|
||||||
// Add to sent folder (mock)
|
// Add to sent folder (mock)
|
||||||
|
// Combine username and domain
|
||||||
|
const fromEmail = `${formData.fromUsername || 'admin'}@${formData.fromDomain || this.emailDomains[0] || 'dcrouter.local'}`;
|
||||||
|
|
||||||
const newEmail: IEmail = {
|
const newEmail: IEmail = {
|
||||||
id: `email-${Date.now()}`,
|
id: `email-${Date.now()}`,
|
||||||
from: formData.from || 'admin@dcrouter.local',
|
from: fromEmail,
|
||||||
to: formData.to || [],
|
to: formData.to || [],
|
||||||
cc: formData.cc || [],
|
cc: formData.cc || [],
|
||||||
bcc: formData.bcc || [],
|
bcc: formData.bcc || [],
|
||||||
|
Reference in New Issue
Block a user