@zhin.js/adapter-email 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +32 -90
- package/adapters/email.ts +29 -0
- package/lib/endpoint.d.ts +25 -32
- package/lib/endpoint.js +181 -323
- package/lib/index.d.ts +3 -10
- package/lib/index.js +3 -23
- package/lib/protocol.d.ts +107 -0
- package/lib/protocol.js +160 -0
- package/lib/transport.d.ts +32 -0
- package/lib/transport.js +27 -0
- package/package.json +36 -7
- package/plugin.ts +8 -0
- package/schema.json +58 -0
- package/src/endpoint.ts +231 -398
- package/src/index.ts +27 -29
- package/src/protocol.ts +269 -0
- package/src/transport.ts +65 -0
- package/lib/adapter.d.ts +0 -14
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -21
- package/lib/adapter.js.map +0 -1
- package/lib/endpoint.d.ts.map +0 -1
- package/lib/endpoint.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/segment-mapper.d.ts +0 -2
- package/lib/segment-mapper.d.ts.map +0 -1
- package/lib/segment-mapper.js +0 -2
- package/lib/segment-mapper.js.map +0 -1
- package/lib/types.d.ts +0 -49
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/src/adapter.ts +0 -24
- package/src/segment-mapper.ts +0 -1
- package/src/types.ts +0 -52
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email SMTP/IMAP helpers (no legacy Adapter/Endpoint / segment-mapper).
|
|
3
|
+
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
4
|
+
*/
|
|
5
|
+
import type { Attachment } from 'mailparser';
|
|
6
|
+
export interface SmtpConfig {
|
|
7
|
+
readonly host: string;
|
|
8
|
+
readonly port: number;
|
|
9
|
+
readonly secure: boolean;
|
|
10
|
+
readonly auth: {
|
|
11
|
+
readonly user: string;
|
|
12
|
+
readonly pass: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface ImapConfig {
|
|
16
|
+
readonly host: string;
|
|
17
|
+
readonly port: number;
|
|
18
|
+
readonly tls: boolean;
|
|
19
|
+
readonly user: string;
|
|
20
|
+
readonly password: string;
|
|
21
|
+
readonly checkInterval?: number;
|
|
22
|
+
readonly mailbox?: string;
|
|
23
|
+
readonly markSeen?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface EmailAttachmentsConfig {
|
|
26
|
+
readonly enabled: boolean;
|
|
27
|
+
readonly downloadPath?: string;
|
|
28
|
+
readonly maxFileSize?: number;
|
|
29
|
+
readonly allowedTypes?: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
32
|
+
export interface EmailAdapterConfig {
|
|
33
|
+
readonly name?: string;
|
|
34
|
+
readonly smtp?: SmtpConfig;
|
|
35
|
+
readonly imap?: ImapConfig;
|
|
36
|
+
readonly attachments?: EmailAttachmentsConfig;
|
|
37
|
+
/** Transitional: legacy root `endpoints[]` with `context: email`. */
|
|
38
|
+
readonly endpoints?: ReadonlyArray<Partial<ResolvedEmailConfig> & {
|
|
39
|
+
readonly context?: string;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
export interface ResolvedEmailConfig {
|
|
43
|
+
readonly context: 'email';
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly smtp: SmtpConfig;
|
|
46
|
+
readonly imap: Required<Pick<ImapConfig, 'checkInterval' | 'mailbox' | 'markSeen'>> & ImapConfig;
|
|
47
|
+
readonly attachments?: {
|
|
48
|
+
readonly enabled: boolean;
|
|
49
|
+
readonly downloadPath: string;
|
|
50
|
+
readonly maxFileSize: number;
|
|
51
|
+
readonly allowedTypes?: readonly string[];
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export interface EmailMessage {
|
|
55
|
+
readonly messageId: string;
|
|
56
|
+
readonly from: string;
|
|
57
|
+
readonly to: readonly string[];
|
|
58
|
+
readonly cc?: readonly string[];
|
|
59
|
+
readonly bcc?: readonly string[];
|
|
60
|
+
readonly subject: string;
|
|
61
|
+
readonly text?: string;
|
|
62
|
+
readonly html?: string;
|
|
63
|
+
readonly attachments: readonly Attachment[];
|
|
64
|
+
readonly date: Date;
|
|
65
|
+
readonly uid: number;
|
|
66
|
+
}
|
|
67
|
+
export interface EmailWireSegment {
|
|
68
|
+
readonly type: string;
|
|
69
|
+
readonly data?: Record<string, unknown>;
|
|
70
|
+
}
|
|
71
|
+
export declare function resolveEmailConfig(config?: EmailAdapterConfig): ResolvedEmailConfig;
|
|
72
|
+
export declare function htmlToText(html: string): string;
|
|
73
|
+
export declare function addressListText(addr: unknown): string[];
|
|
74
|
+
export declare function parseEmailMessage(parsed: {
|
|
75
|
+
messageId?: string;
|
|
76
|
+
from?: unknown;
|
|
77
|
+
to?: unknown;
|
|
78
|
+
cc?: unknown;
|
|
79
|
+
bcc?: unknown;
|
|
80
|
+
subject?: string;
|
|
81
|
+
text?: string;
|
|
82
|
+
html?: string | false;
|
|
83
|
+
attachments?: Attachment[];
|
|
84
|
+
date?: Date;
|
|
85
|
+
}, uid: number): EmailMessage;
|
|
86
|
+
/** Build inbound text for MessageGateway.receive (gateway owns reply routing). */
|
|
87
|
+
export declare function formatInboundContent(email: EmailMessage): string;
|
|
88
|
+
export declare function senderDisplayName(from: string): string;
|
|
89
|
+
/**
|
|
90
|
+
* Wire-encode an already-rendered outbound payload into nodemailer options.
|
|
91
|
+
* Segment canonicalization is intentionally not done here.
|
|
92
|
+
*/
|
|
93
|
+
export declare function formatOutboundMail(payload: unknown, options: {
|
|
94
|
+
readonly from: string;
|
|
95
|
+
readonly to: string;
|
|
96
|
+
readonly subject?: string;
|
|
97
|
+
}): {
|
|
98
|
+
from: string;
|
|
99
|
+
to: string;
|
|
100
|
+
subject: string;
|
|
101
|
+
text?: string;
|
|
102
|
+
html?: string;
|
|
103
|
+
attachments?: Array<{
|
|
104
|
+
filename: string;
|
|
105
|
+
path: string;
|
|
106
|
+
}>;
|
|
107
|
+
};
|
package/lib/protocol.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email SMTP/IMAP helpers (no legacy Adapter/Endpoint / segment-mapper).
|
|
3
|
+
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
4
|
+
*/
|
|
5
|
+
import { htmlToPlainTextWithBlockBreaks } from '@zhin.js/core';
|
|
6
|
+
export function resolveEmailConfig(config = {}) {
|
|
7
|
+
const entry = config.endpoints?.find((item) => item.context === 'email');
|
|
8
|
+
const smtp = config.smtp ?? entry?.smtp;
|
|
9
|
+
const imap = config.imap ?? entry?.imap;
|
|
10
|
+
if (!smtp?.host || !smtp.auth?.user || !imap?.host || !imap.user) {
|
|
11
|
+
throw new TypeError('Email adapter requires smtp + imap config (plugins.<key>.smtp/imap or endpoints with context: email)');
|
|
12
|
+
}
|
|
13
|
+
const name = (typeof config.name === 'string' && config.name)
|
|
14
|
+
|| (typeof entry?.name === 'string' && entry.name)
|
|
15
|
+
|| process.env.EMAIL_BOT_NAME
|
|
16
|
+
|| 'email-bot';
|
|
17
|
+
const attachmentsSource = config.attachments ?? entry?.attachments;
|
|
18
|
+
const attachments = attachmentsSource?.enabled
|
|
19
|
+
? {
|
|
20
|
+
enabled: true,
|
|
21
|
+
downloadPath: attachmentsSource.downloadPath || './downloads/email',
|
|
22
|
+
maxFileSize: attachmentsSource.maxFileSize || 10 * 1024 * 1024,
|
|
23
|
+
allowedTypes: attachmentsSource.allowedTypes,
|
|
24
|
+
}
|
|
25
|
+
: undefined;
|
|
26
|
+
return {
|
|
27
|
+
context: 'email',
|
|
28
|
+
name,
|
|
29
|
+
smtp,
|
|
30
|
+
imap: {
|
|
31
|
+
...imap,
|
|
32
|
+
checkInterval: imap.checkInterval ?? 60_000,
|
|
33
|
+
mailbox: imap.mailbox ?? 'INBOX',
|
|
34
|
+
markSeen: imap.markSeen !== false,
|
|
35
|
+
},
|
|
36
|
+
attachments,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function htmlToText(html) {
|
|
40
|
+
return htmlToPlainTextWithBlockBreaks(html);
|
|
41
|
+
}
|
|
42
|
+
export function addressListText(addr) {
|
|
43
|
+
if (!addr)
|
|
44
|
+
return [];
|
|
45
|
+
if (Array.isArray(addr)) {
|
|
46
|
+
return addr.map((item) => addressText(item));
|
|
47
|
+
}
|
|
48
|
+
return [addressText(addr)];
|
|
49
|
+
}
|
|
50
|
+
function addressText(addr) {
|
|
51
|
+
if (!addr || typeof addr !== 'object')
|
|
52
|
+
return String(addr ?? '');
|
|
53
|
+
const record = addr;
|
|
54
|
+
return record.text || record.address || String(addr);
|
|
55
|
+
}
|
|
56
|
+
export function parseEmailMessage(parsed, uid) {
|
|
57
|
+
return {
|
|
58
|
+
messageId: parsed.messageId || '',
|
|
59
|
+
from: parsed.from ? addressListText(parsed.from)[0] || '' : '',
|
|
60
|
+
to: addressListText(parsed.to),
|
|
61
|
+
cc: addressListText(parsed.cc),
|
|
62
|
+
bcc: addressListText(parsed.bcc),
|
|
63
|
+
subject: parsed.subject || '',
|
|
64
|
+
text: parsed.text || '',
|
|
65
|
+
html: parsed.html ? String(parsed.html) : '',
|
|
66
|
+
attachments: parsed.attachments || [],
|
|
67
|
+
date: parsed.date || new Date(),
|
|
68
|
+
uid,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Build inbound text for MessageGateway.receive (gateway owns reply routing). */
|
|
72
|
+
export function formatInboundContent(email) {
|
|
73
|
+
const parts = [];
|
|
74
|
+
if (email.subject)
|
|
75
|
+
parts.push(`Subject: ${email.subject}`, '');
|
|
76
|
+
if (email.text) {
|
|
77
|
+
parts.push(email.text);
|
|
78
|
+
}
|
|
79
|
+
else if (email.html) {
|
|
80
|
+
const fromHtml = htmlToText(email.html);
|
|
81
|
+
if (fromHtml)
|
|
82
|
+
parts.push(fromHtml);
|
|
83
|
+
}
|
|
84
|
+
for (const attachment of email.attachments) {
|
|
85
|
+
const kind = attachment.contentType?.startsWith('image/') ? 'image' : 'file';
|
|
86
|
+
const name = attachment.filename || 'attachment';
|
|
87
|
+
parts.push(`[${kind}: ${name}]`);
|
|
88
|
+
}
|
|
89
|
+
const text = parts.join('\n').trim();
|
|
90
|
+
return text || '(Empty email)';
|
|
91
|
+
}
|
|
92
|
+
export function senderDisplayName(from) {
|
|
93
|
+
const name = from.split('<')[0]?.trim();
|
|
94
|
+
return name || from;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Wire-encode an already-rendered outbound payload into nodemailer options.
|
|
98
|
+
* Segment canonicalization is intentionally not done here.
|
|
99
|
+
*/
|
|
100
|
+
export function formatOutboundMail(payload, options) {
|
|
101
|
+
const mail = {
|
|
102
|
+
from: options.from,
|
|
103
|
+
to: options.to,
|
|
104
|
+
subject: options.subject ?? 'Message from Bot',
|
|
105
|
+
};
|
|
106
|
+
if (typeof payload === 'string') {
|
|
107
|
+
return { ...mail, text: payload };
|
|
108
|
+
}
|
|
109
|
+
const segments = Array.isArray(payload)
|
|
110
|
+
? payload
|
|
111
|
+
: payload && typeof payload === 'object' && 'type' in payload
|
|
112
|
+
? [payload]
|
|
113
|
+
: [];
|
|
114
|
+
if (segments.length === 0) {
|
|
115
|
+
return {
|
|
116
|
+
...mail,
|
|
117
|
+
text: payload == null ? '' : typeof payload === 'object'
|
|
118
|
+
? JSON.stringify(payload)
|
|
119
|
+
: String(payload),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const textParts = [];
|
|
123
|
+
const htmlParts = [];
|
|
124
|
+
const attachments = [];
|
|
125
|
+
for (const item of segments) {
|
|
126
|
+
if (typeof item === 'string') {
|
|
127
|
+
textParts.push(item);
|
|
128
|
+
htmlParts.push(item.replace(/\n/g, '<br>'));
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const data = item.data ?? {};
|
|
132
|
+
switch (item.type) {
|
|
133
|
+
case 'text': {
|
|
134
|
+
const textContent = String(data.text ?? data.content ?? '');
|
|
135
|
+
textParts.push(textContent);
|
|
136
|
+
htmlParts.push(textContent.replace(/\n/g, '<br>'));
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case 'image':
|
|
140
|
+
case 'file': {
|
|
141
|
+
if (typeof data.url === 'string' && data.url) {
|
|
142
|
+
attachments.push({
|
|
143
|
+
filename: String(data.filename || (item.type === 'image' ? 'image.png' : 'file')),
|
|
144
|
+
path: data.url,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
default:
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
...mail,
|
|
155
|
+
...(textParts.length > 0
|
|
156
|
+
? { text: textParts.join('\n'), html: htmlParts.join('<br>') }
|
|
157
|
+
: {}),
|
|
158
|
+
...(attachments.length > 0 ? { attachments } : {}),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ResolvedEmailConfig } from './protocol.js';
|
|
2
|
+
export interface EmailSmtpTransport {
|
|
3
|
+
verify(): Promise<void>;
|
|
4
|
+
sendMail(options: unknown): Promise<{
|
|
5
|
+
messageId?: string;
|
|
6
|
+
}>;
|
|
7
|
+
close(): void;
|
|
8
|
+
}
|
|
9
|
+
export interface EmailImapTransport {
|
|
10
|
+
once(event: 'ready' | 'error', listener: (...args: unknown[]) => void): void;
|
|
11
|
+
on(event: string, listener: (...args: unknown[]) => void): void;
|
|
12
|
+
connect(): void;
|
|
13
|
+
end(): void;
|
|
14
|
+
openBox(mailbox: string, openReadWrite: boolean, callback: (error: Error | null, box?: unknown) => void): void;
|
|
15
|
+
search(criteria: string[], callback: (error: Error | null, results: number[]) => void): void;
|
|
16
|
+
fetch(results: number[], options: {
|
|
17
|
+
bodies: string;
|
|
18
|
+
markSeen?: boolean;
|
|
19
|
+
}): {
|
|
20
|
+
on(event: 'message', listener: (msg: EmailImapFetchMessage, seqno: number) => void): void;
|
|
21
|
+
once(event: 'error' | 'end', listener: (error?: Error) => void): void;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface EmailImapFetchMessage {
|
|
25
|
+
on(event: 'body', listener: (stream: NodeJS.ReadableStream) => void): void;
|
|
26
|
+
once(event: 'attributes', listener: (attrs: {
|
|
27
|
+
uid?: number;
|
|
28
|
+
}) => void): void;
|
|
29
|
+
once(event: 'end', listener: () => void): void;
|
|
30
|
+
}
|
|
31
|
+
export declare function defaultCreateSmtp(config: ResolvedEmailConfig['smtp']): EmailSmtpTransport;
|
|
32
|
+
export declare function defaultCreateImap(config: ResolvedEmailConfig['imap']): EmailImapTransport;
|
package/lib/transport.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email SMTP/IMAP transport factories (nodemailer + imap).
|
|
3
|
+
*/
|
|
4
|
+
import nodemailer from 'nodemailer';
|
|
5
|
+
import Imap from 'imap';
|
|
6
|
+
export function defaultCreateSmtp(config) {
|
|
7
|
+
const transporter = nodemailer.createTransport({
|
|
8
|
+
host: config.host,
|
|
9
|
+
port: config.port,
|
|
10
|
+
secure: config.secure,
|
|
11
|
+
auth: { user: config.auth.user, pass: config.auth.pass },
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
verify: () => transporter.verify().then(() => undefined),
|
|
15
|
+
sendMail: (options) => transporter.sendMail(options),
|
|
16
|
+
close: () => transporter.close(),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function defaultCreateImap(config) {
|
|
20
|
+
return new Imap({
|
|
21
|
+
user: config.user,
|
|
22
|
+
password: config.password,
|
|
23
|
+
host: config.host,
|
|
24
|
+
port: config.port,
|
|
25
|
+
tls: config.tls,
|
|
26
|
+
});
|
|
27
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-email",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Zhin.js adapter for
|
|
5
|
+
"description": "Zhin.js Email adapter for Plugin Runtime (SMTP/IMAP)",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"imap": "^0.8.19",
|
|
10
10
|
"mailparser": "^3.9.14",
|
|
11
|
-
"nodemailer": "^9.0.3"
|
|
11
|
+
"nodemailer": "^9.0.3",
|
|
12
|
+
"@zhin.js/adapter": "1.0.1",
|
|
13
|
+
"@zhin.js/core": "1.3.5",
|
|
14
|
+
"@zhin.js/logger": "1.0.75",
|
|
15
|
+
"@zhin.js/plugin-runtime": "1.0.1"
|
|
12
16
|
},
|
|
13
17
|
"peerDependencies": {
|
|
14
|
-
"zhin.js": "
|
|
18
|
+
"@zhin.js/adapter": "1.0.1",
|
|
19
|
+
"@zhin.js/core": "1.3.5",
|
|
20
|
+
"@zhin.js/plugin-runtime": "1.0.1",
|
|
21
|
+
"zhin.js": "4.1.3"
|
|
22
|
+
},
|
|
23
|
+
"peerDependenciesMeta": {
|
|
24
|
+
"zhin.js": {
|
|
25
|
+
"optional": true
|
|
26
|
+
}
|
|
15
27
|
},
|
|
16
28
|
"devDependencies": {
|
|
17
29
|
"@types/imap": "^0.8.40",
|
|
@@ -19,7 +31,7 @@
|
|
|
19
31
|
"@types/node": "^26.1.0",
|
|
20
32
|
"@types/nodemailer": "^8.0.0",
|
|
21
33
|
"typescript": "^6.0.3",
|
|
22
|
-
"
|
|
34
|
+
"vitest": "^4.1.10"
|
|
23
35
|
},
|
|
24
36
|
"keywords": [
|
|
25
37
|
"zhin",
|
|
@@ -43,6 +55,9 @@
|
|
|
43
55
|
"directory": "plugins/adapters/email"
|
|
44
56
|
},
|
|
45
57
|
"files": [
|
|
58
|
+
"adapters",
|
|
59
|
+
"plugin.ts",
|
|
60
|
+
"schema.json",
|
|
46
61
|
"src",
|
|
47
62
|
"lib",
|
|
48
63
|
"agent",
|
|
@@ -63,9 +78,23 @@
|
|
|
63
78
|
"engines": {
|
|
64
79
|
"node": "^20.19.0 || >=22.12.0"
|
|
65
80
|
},
|
|
81
|
+
"zhin": {
|
|
82
|
+
"protocol": 1,
|
|
83
|
+
"type": "plugin",
|
|
84
|
+
"entry": "./plugin.ts",
|
|
85
|
+
"engine": "^1.0.0",
|
|
86
|
+
"runtime": "trusted",
|
|
87
|
+
"features": [
|
|
88
|
+
{
|
|
89
|
+
"package": "@zhin.js/adapter",
|
|
90
|
+
"api": "^1.0.0"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"plugins": []
|
|
94
|
+
},
|
|
66
95
|
"scripts": {
|
|
67
|
-
"build": "
|
|
96
|
+
"build": "tsc",
|
|
68
97
|
"clean": "rimraf lib",
|
|
69
|
-
"
|
|
98
|
+
"test": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/adapters/email/tests"
|
|
70
99
|
}
|
|
71
100
|
}
|
package/plugin.ts
ADDED
package/schema.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"additionalProperties": false,
|
|
5
|
+
"properties": {
|
|
6
|
+
"name": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"default": "email-bot"
|
|
9
|
+
},
|
|
10
|
+
"smtp": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"additionalProperties": false,
|
|
13
|
+
"properties": {
|
|
14
|
+
"host": { "type": "string" },
|
|
15
|
+
"port": { "type": "number" },
|
|
16
|
+
"secure": { "type": "boolean" },
|
|
17
|
+
"auth": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"properties": {
|
|
21
|
+
"user": { "type": "string" },
|
|
22
|
+
"pass": { "type": "string" }
|
|
23
|
+
},
|
|
24
|
+
"required": ["user", "pass"]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": ["host", "port", "secure", "auth"]
|
|
28
|
+
},
|
|
29
|
+
"imap": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"properties": {
|
|
33
|
+
"host": { "type": "string" },
|
|
34
|
+
"port": { "type": "number" },
|
|
35
|
+
"tls": { "type": "boolean" },
|
|
36
|
+
"user": { "type": "string" },
|
|
37
|
+
"password": { "type": "string" },
|
|
38
|
+
"checkInterval": { "type": "number", "default": 60000 },
|
|
39
|
+
"mailbox": { "type": "string", "default": "INBOX" },
|
|
40
|
+
"markSeen": { "type": "boolean", "default": true }
|
|
41
|
+
},
|
|
42
|
+
"required": ["host", "port", "tls", "user", "password"]
|
|
43
|
+
},
|
|
44
|
+
"attachments": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"additionalProperties": false,
|
|
47
|
+
"properties": {
|
|
48
|
+
"enabled": { "type": "boolean", "default": false },
|
|
49
|
+
"downloadPath": { "type": "string" },
|
|
50
|
+
"maxFileSize": { "type": "number" },
|
|
51
|
+
"allowedTypes": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"items": { "type": "string" }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|