diff --git a/lib/account.js b/lib/account.js index 7b3a6c2bc..f1af8e866 100644 --- a/lib/account.js +++ b/lib/account.js @@ -96,7 +96,7 @@ class Account { accountData.oauth2 && accountData.oauth2.provider && accountData.oauth2.provider !== accountData.type ? accountData.oauth2.provider : undefined, - state: !runIndex || runIndex <= accountData.runIndex ? accountData.state : 'init', + state: !runIndex || runIndex <= accountData.runIndex || ['init', 'unset'].includes(accountData.state) ? accountData.state : 'init', webhooks: accountData.webhooks || undefined, proxy: accountData.proxy || undefined, @@ -447,7 +447,7 @@ class Account { let accountData = this.unserializeAccountData(result); - accountData.state = !runIndex || runIndex <= accountData.runIndex ? accountData.state : 'init'; + accountData.state = !runIndex || runIndex <= accountData.runIndex || ['init', 'unset'].includes(accountData.state) ? accountData.state : 'init'; if (requireValid && !['connected', 'connecting', 'syncing'].includes(accountData.state)) { let err; @@ -1874,7 +1874,7 @@ class Account { if (data.reconnect) { await this.call({ - cmd: 'update', + cmd: 'reconnect', account: this.account, timeout: this.timeout }); diff --git a/lib/api-client/base-client.js b/lib/api-client/base-client.js index e55ae10f9..1b4e65d8a 100644 --- a/lib/api-client/base-client.js +++ b/lib/api-client/base-client.js @@ -38,6 +38,10 @@ class BaseClient { return null; } + async reconnect() { + return null; + } + async subconnections() { return []; } diff --git a/lib/autodetect-imap-settings.js b/lib/autodetect-imap-settings.js index 51f07fec7..888a46288 100644 --- a/lib/autodetect-imap-settings.js +++ b/lib/autodetect-imap-settings.js @@ -341,6 +341,7 @@ async function resolveUsingMX(email, domain) { return await resolveUsingAutoconfig(email, 'zone.ee', 'mx'); } + // AWS WorkMail let awsMatch = exchange.match(/inbound-smtp\.([^.]+)\.amazonaws.com/); if (awsMatch) { let region = awsMatch[1].toLowerCase().trim(); @@ -359,6 +360,7 @@ async function resolveUsingMX(email, domain) { }; } + // Zoho EU if (/^mx\d*\.zoho\.eu$/i.test(exchange)) { // Zoho custom domain in EU return { @@ -376,6 +378,7 @@ async function resolveUsingMX(email, domain) { }; } + // Zoho international if (/^mx\d*\.zoho\.com$/i.test(exchange)) { // Zoho custom domain not in EU return { @@ -393,6 +396,7 @@ async function resolveUsingMX(email, domain) { }; } + // MS365 if (/\bprotection\.outlook\.com$/i.test(exchange)) { // outlook // as autodiscovery is currently (2021-11-17) closed use a fixed response @@ -427,6 +431,25 @@ async function resolveUsingMX(email, domain) { }; } + // Alibaba Mail + if (/^mx\d*\.sg\.aliyun\.com$/i.test(exchange)) { + // Naver.com + return { + imap: { + host: 'imap.sg.aliyun.com', + port: 993, + secure: true + }, + smtp: { + host: 'smtp.sg.aliyun.com', + port: 465, + secure: true + }, + _source: 'mx' + }; + } + + // Naver (kr) if (/^mx\d*\.naver\.com$/i.test(exchange)) { // Naver.com return { diff --git a/lib/routes-ui.js b/lib/routes-ui.js index f2ae577fc..419617b08 100644 --- a/lib/routes-ui.js +++ b/lib/routes-ui.js @@ -7008,7 +7008,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} try { request.logger.info({ msg: 'Request reconnect for logging', account }); try { - await call({ cmd: 'update', account }); + await call({ cmd: 'reconnect', account }); } catch (err) { request.logger.error({ msg: 'Reconnect request failed', action: 'request_reconnect', account, err }); } diff --git a/server.js b/server.js index 54e1e0a65..d5ece10d6 100644 --- a/server.js +++ b/server.js @@ -1846,6 +1846,7 @@ async function onCommand(worker, message) { case 'sync': case 'pause': case 'resume': + case 'reconnect': if (assigned.has(message.account)) { let assignedWorker = assigned.get(message.account); call(assignedWorker, message) diff --git a/workers/imap.js b/workers/imap.js index 74dfe816c..652fe2662 100644 --- a/workers/imap.js +++ b/workers/imap.js @@ -130,6 +130,14 @@ class ConnectionHandler { async assignConnection(account, runIndex) { logger.info({ msg: 'Assigned account to worker', account }); + if (!this.runIndex) { + this.runIndex = runIndex; + } + + if (!runIndex && this.runIndex) { + runIndex = this.runIndex; + } + let accountLogger = await this.getAccountLogger(account); let secret = await getSecret(); let accountObject = new Account({ @@ -278,6 +286,25 @@ class ConnectionHandler { } } + async reconnectConnection(account) { + logger.info({ msg: 'Account reconnection requested', account }); + if (this.accounts.has(account)) { + let accountObject = this.accounts.get(account); + if (accountObject.connection) { + accountObject.connection.accountLogger.log({ + level: 'info', + t: Date.now(), + cid: accountObject.connection.cid, + msg: 'Account reconnection requested' + }); + + await accountObject.connection.close(); + } + + await this.assignConnection(account); + } + } + async listMessages(message) { if (!this.accounts.has(message.account)) { return NO_ACTIVE_HANDLER_RESP; @@ -634,6 +661,7 @@ class ConnectionHandler { case 'sync': case 'pause': case 'resume': + case 'reconnect': return await this[`${message.cmd}Connection`](message.account); case 'assign':