Skip to content

Commit d88fbfb

Browse files
committed
fix: added eM Client guide, bumped @ladjs/graceful to handle uncaughtExceptions (e.g. undici) otherwise processes restart, added agent.destroy(), optimizations to sync paid alias allowlist job (still needs tested and monitored, extremely slow and long running)
1 parent a9eef13 commit d88fbfb

File tree

9 files changed

+723
-673
lines changed

9 files changed

+723
-673
lines changed

app/models/aliases.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ const Aliases = new mongoose.Schema({
349349
});
350350

351351
// compound index
352+
Aliases.index({ domain: 1, is_enabled: 1, user: 1, _id: 1 });
352353
Aliases.index({ user: 1, domain: 1 });
353354
Aliases.index({ _id: 1, domain: 1 });
354355
Aliases.index({ name: 1, domain: 1 });

app/models/domains.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,8 @@ const Domains = new mongoose.Schema({
498498
tokens: [Token]
499499
});
500500

501+
Domains.index({ plan: 1, has_txt_record: 1, _id: 1 });
502+
501503
Domains.index(
502504
{ smtp_suspended_sent_at: 1 },
503505
{

app/views/faq/index.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* [Thunderbird](#thunderbird)
1616
* [Microsoft Outlook](#microsoft-outlook)
1717
* [Apple Mail](#apple-mail)
18+
* [eM Client](#em-client)
1819
* [Mobile Devices](#mobile-devices)
1920
* [Postfix SMTP Relay Configuration](#postfix-smtp-relay-configuration)
2021
* [How to Send Mail As using Gmail](#how-to-send-mail-as-using-gmail)
@@ -275,6 +276,20 @@ Everything is done in-memory and [our source code is on GitHub](https://github.c
275276
* Password: Your generated password
276277
6. Click **Sign In**
277278

279+
### eM Client
280+
281+
1. Create a new alias and generate a password in your Forward Email dashboard
282+
2. Open eM Client and go to **Menu → Accounts → + Add Account**
283+
3. Click on **Mail** and then select **Other**
284+
4. Enter your Forward Email address and click **Next**
285+
5. Enter the following server settings:
286+
* **Incoming server**: `imap.forwardemail.net`
287+
* **Outgoing server**: `smtp.forwardemail.net`
288+
6. Enter your full email address as the **User name** and your generated password as the **Password** for both incoming and outgoing servers.
289+
7. eM Client will test the connection. Once it passes, click **Next**.
290+
8. Enter your name and choose an account name.
291+
9. Click **Finish**.
292+
278293
### Mobile Devices
279294

280295
For iOS:
@@ -3216,9 +3231,9 @@ We publish our IP addresses at <https://forwardemail.net/ips>.
32163231

32173232
Yes, we have a [list of domain name extensions](#what-domain-name-extensions-are-allowlisted-by-default) that are allowlisted by default and a dynamic, cached, and rolling allowlist based off [strict criteria](#what-is-your-allowlist-criteria).
32183233

3219-
All domains, emails, and IP addresses used by paying customers are automatically checked against our denylist hourly &ndash; which alerts admins who can manually intervene if necessary.
3234+
All domains, emails, and IP addresses used by paying customers are automatically checked against our denylist hourly which alerts admins who can manually intervene if necessary.
32203235

3221-
Additionally, if one of your domains or its email addresses are denylisted (e.g. for sending spam, viruses, or due to impersonation attacks) &ndash; then the domain admins (you) and our team admins will be notified by email immediately. We strongly recommend that you [configure DMARC](#how-do-i-set-up-dmarc-for-forward-email) to prevent this.
3236+
Additionally, if one of your domains or its email addresses are denylisted (e.g. for sending spam, viruses, or due to impersonation attacks) then the domain admins (you) and our team admins will be notified by email immediately. We strongly recommend that you [configure DMARC](#how-do-i-set-up-dmarc-for-forward-email) to prevent this.
32223237

32233238
### What domain name extensions are allowlisted by default
32243239

helpers/retry-client.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class RetryClient extends undici.Client {
8585
const ms = calculateDelay(count);
8686
if (ms) await timers.setTimeout(ms);
8787
return this.request(options, count + 1);
88+
} finally {
89+
if (options.dispatcher) options.dispatcher.destroy();
8890
}
8991
};
9092
}

helpers/retry-request.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ async function retryRequest(url, opts = {}, count = 1) {
9494
const ms = opts.calculateDelay(count);
9595
if (ms) await timers.setTimeout(ms);
9696
return retryRequest(url, opts, count + 1);
97+
} finally {
98+
if (opts.dispatcher) opts.dispatcher.destroy();
9799
}
98100
}
99101

helpers/wkd.js

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -57,38 +57,40 @@ function WKD(resolver, client) {
5757
new TimeoutError(`${url} took longer than ${DURATION}`)
5858
);
5959
}, ms(DURATION));
60+
const dispatcher = new undici.Agent({
61+
headersTimeout: ms(DURATION),
62+
connectTimeout: ms(DURATION),
63+
bodyTimeout: ms(DURATION),
64+
//
65+
//
66+
// TODO: there is a bug in tangerine where if we supply
67+
// a custom resolver in self-hosted mode then
68+
// it causes an uncaught exception it appears
69+
//
70+
//
71+
// TODO: an uncaught exception occurs here in self hosting sometimes (?)
72+
// TypeError: Cannot read properties of undefined (reading 'length')
73+
// (which means it occurs in tangerine under the hood)
74+
//
75+
...(config.isSelfHosted
76+
? {}
77+
: {
78+
connect: {
79+
lookup(hostname, options, fn) {
80+
resolver
81+
.lookup(hostname, options)
82+
.then((result) => {
83+
fn(null, result?.address, result?.family);
84+
})
85+
.catch((err) => fn(err));
86+
}
87+
}
88+
})
89+
});
6090
const response = await undici.fetch(url, {
6191
signal: abortController.signal,
62-
dispatcher: new undici.Agent({
63-
headersTimeout: ms(DURATION),
64-
connectTimeout: ms(DURATION),
65-
bodyTimeout: ms(DURATION),
66-
//
67-
//
68-
// TODO: there is a bug in tangerine where if we supply
69-
// a custom resolver in self-hosted mode then
70-
// it causes an uncaught exception it appears
71-
//
72-
//
73-
// TODO: an uncaught exception occurs here in self hosting sometimes (?)
74-
// TypeError: Cannot read properties of undefined (reading 'length')
75-
// (which means it occurs in tangerine under the hood)
76-
//
77-
...(config.isSelfHosted
78-
? {}
79-
: {
80-
connect: {
81-
lookup(hostname, options, fn) {
82-
resolver
83-
.lookup(hostname, options)
84-
.then((result) => {
85-
fn(null, result?.address, result?.family);
86-
})
87-
.catch((err) => fn(err));
88-
}
89-
}
90-
})
91-
})
92+
dispatcher
93+
// TODO: may need `dispatcher.destroy()`, but not sure since we use `undici.fetch` vs `undici.request`
9294
});
9395
clearTimeout(t);
9496
return response;

0 commit comments

Comments
 (0)