Merge pull request 'docs(email): mail-client autodiscovery + external-DNS records' (#2) from docs/mail-autodiscovery into main
Build and deploy / deploy (push) Successful in 29s
Build and deploy / deploy (push) Successful in 29s
Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 369 KiB |
@@ -34,9 +34,41 @@ import Support from '~/content/partials/support-link.mdx';
|
|||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
|
## Auto-configure your mail app
|
||||||
|
|
||||||
|
Most modern mail apps — Outlook, Apple Mail, Thunderbird, and the iOS and Android mail apps — can set themselves up from your domain's DNS. You enter your **full email address** and **password**, and the app finds the right servers, ports, and security settings on its own.
|
||||||
|
|
||||||
|
**If your domain uses our nameservers, this already works** — we add the necessary records automatically when you add the domain, so there's nothing for you to do.
|
||||||
|
|
||||||
|
### If your DNS is hosted elsewhere
|
||||||
|
|
||||||
|
If your domain's DNS lives at another provider (Cloudflare, GoDaddy, Namecheap, and so on), your mail app can't auto-configure until you add a few records there yourself. The Email page builds the exact records for you: open the **Mail Client Setup** section, pick the domain, and copy them in.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Add these records to the domain's zone at your DNS provider. The names are **relative to your domain** — most providers fill in the rest automatically, so `autoconfig` becomes `autoconfig.example.com`.
|
||||||
|
|
||||||
|
| Type | Name | Priority | Weight | Port | Value |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| CNAME | `autoconfig` | — | — | — | your mail server |
|
||||||
|
| SRV | `_autodiscover._tcp` | 0 | 0 | 443 | your mail server |
|
||||||
|
| SRV | `_imaps._tcp` | 0 | 1 | 993 | your mail server |
|
||||||
|
| SRV | `_submission._tcp` | 0 | 1 | 587 | your mail server |
|
||||||
|
| SRV | `_pop3s._tcp` | 0 | 1 | 995 | your mail server |
|
||||||
|
|
||||||
|
Use the **mail server hostname shown in the Mail Client Setup section** as the value — it's the same host your **MX** record points at. The `_pop3s` record is only needed if you read mail over POP3 instead of IMAP. Click **Copy records** to grab them all at once in zone-file format.
|
||||||
|
|
||||||
|
<Aside type="tip">
|
||||||
|
If your provider has a proxy toggle (such as Cloudflare's orange cloud), keep these records **DNS only** — proxying them stops mail clients from reading them.
|
||||||
|
</Aside>
|
||||||
|
|
||||||
|
<Aside type="note">
|
||||||
|
These records only help apps *find* the server. You still create the mailbox in WHP first, and your domain's **MX** record must point at our mail server for mail to be delivered.
|
||||||
|
</Aside>
|
||||||
|
|
||||||
## Set up your email client
|
## Set up your email client
|
||||||
|
|
||||||
The exact IMAP, POP3, and SMTP hostnames are listed on the Email page — click **Setup Instructions → View Instructions** under **Mail Server Access** for a step-by-step that includes the right hostnames, ports, and security settings for your server.
|
Most apps configure themselves from the records above once you enter your address and password. If yours doesn't support that — or you'd rather enter the settings by hand — the exact IMAP, POP3, and SMTP hostnames are listed on the Email page: click **Setup Instructions → View Instructions** under **Mail Server Access** for a step-by-step that includes the right hostnames, ports, and security settings for your server.
|
||||||
|
|
||||||
The typical settings look like this; substitute the hostname shown in the Setup Instructions:
|
The typical settings look like this; substitute the hostname shown in the Setup Instructions:
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ Each domain starts with a standard zone created automatically when the domain wa
|
|||||||
Editing **MX**, **NS**, or the SPF/DKIM **TXT** records can break email delivery or hand DNS control away from us. Only change these if you know exactly what you're doing.
|
Editing **MX**, **NS**, or the SPF/DKIM **TXT** records can break email delivery or hand DNS control away from us. Only change these if you know exactly what you're doing.
|
||||||
</Aside>
|
</Aside>
|
||||||
|
|
||||||
|
## Mail autodiscovery records
|
||||||
|
|
||||||
|
When we host your DNS, the records that let mail apps configure themselves — an `autoconfig` CNAME plus a set of `_autodiscover` / `_imaps` / `_submission` / `_pop3s` **SRV** records — are already in your zone. You don't need to add them.
|
||||||
|
|
||||||
|
If your DNS is at another provider, add them there by hand. WHP builds the exact records for each domain on the **Email** page — see [Auto-configure your mail app](/whp/how-to/create-an-email-account/#auto-configure-your-mail-app).
|
||||||
|
|
||||||
## Add a record
|
## Add a record
|
||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Email capture — the customer "Mail Client Setup" section on the Email page.
|
||||||
|
*
|
||||||
|
* Captures, as the demo customer:
|
||||||
|
* - whp-email-autodiscovery.png the Mail Client Setup accordion section,
|
||||||
|
* expanded, with the per-domain autodiscovery
|
||||||
|
* DNS records table + copyable zone block.
|
||||||
|
*
|
||||||
|
* Viewport-only (1440x900), redacted for our multi-server fleet: the mail-server
|
||||||
|
* hostname becomes a neutral placeholder, while the brand demo domain
|
||||||
|
* (whp-demo.anhh.co) is kept visible on purpose.
|
||||||
|
*
|
||||||
|
* Read-only: expands an accordion section for the screenshot, never saves.
|
||||||
|
*/
|
||||||
|
import { chromium, type Page } from 'playwright';
|
||||||
|
import { mkdir } from 'node:fs/promises';
|
||||||
|
import { resolve, dirname } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const OUT_DIR = resolve(__dirname, '../../src/assets/screenshots/whp');
|
||||||
|
|
||||||
|
function need(name: string): string {
|
||||||
|
const v = process.env[name];
|
||||||
|
if (!v) throw new Error(`missing env: ${name}`);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BASE = need('WHP_BASE');
|
||||||
|
const USER = need('WHP_USER');
|
||||||
|
const PASS = need('WHP_PASS');
|
||||||
|
|
||||||
|
const HIDE_CSS = `.navbar-text, .brand-full { visibility: hidden !important; }`;
|
||||||
|
|
||||||
|
async function login(page: Page) {
|
||||||
|
await page.goto(`${BASE}/login.php`, { waitUntil: 'domcontentloaded' });
|
||||||
|
await page.fill('input[name="user"]', USER);
|
||||||
|
await page.fill('input[name="password"]', PASS);
|
||||||
|
await page.click('button[type="submit"]');
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Neutralise fleet-identifying text before the screenshot. The brand demo
|
||||||
|
* domain (anhh.co) is intentionally preserved; the mail-server host and any
|
||||||
|
* server hostnames/IPs are swapped for placeholders.
|
||||||
|
*/
|
||||||
|
async function redact(page: Page) {
|
||||||
|
await page.addStyleTag({ content: HIDE_CSS });
|
||||||
|
await page.evaluate(() => {
|
||||||
|
const swaps: [RegExp, string][] = [
|
||||||
|
[/mail\d+\.cloud-hosting\.io/gi, '<mail-server>.cloud-hosting.io'],
|
||||||
|
[/whp\d+(-[a-z0-9]+)?\.cloud-hosting\.io/gi, '<your-server>.cloud-hosting.io'],
|
||||||
|
[/WHP\d+(-[A-Z0-9]+)?\b/g, '<YOUR-SERVER>'],
|
||||||
|
[/whp\d+(-[a-z0-9]+)?\b/gi, '<your-server>'],
|
||||||
|
[/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, '<server-IP>'],
|
||||||
|
];
|
||||||
|
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
|
||||||
|
const nodes: Text[] = [];
|
||||||
|
let n: Node | null = walker.nextNode();
|
||||||
|
while (n) { nodes.push(n as Text); n = walker.nextNode(); }
|
||||||
|
for (const node of nodes) {
|
||||||
|
let v = node.nodeValue ?? '';
|
||||||
|
for (const [re, rep] of swaps) v = v.replace(re, rep);
|
||||||
|
if (v !== node.nodeValue) node.nodeValue = v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await mkdir(OUT_DIR, { recursive: true });
|
||||||
|
const browser = await chromium.launch({ headless: true });
|
||||||
|
const ctx = await browser.newContext({
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
viewport: { width: 1440, height: 900 },
|
||||||
|
deviceScaleFactor: 2,
|
||||||
|
});
|
||||||
|
const page = await ctx.newPage();
|
||||||
|
try {
|
||||||
|
await login(page);
|
||||||
|
await page.goto(`${BASE}/index.php?page=email-management`, { waitUntil: 'networkidle' });
|
||||||
|
|
||||||
|
// Expand the (collapsed-by-default) "Mail Client Setup" accordion section.
|
||||||
|
await page.locator('button[data-bs-target="#mail-client-setup"]').click();
|
||||||
|
await page.waitForSelector('#custMailDnsDomain', { state: 'visible' });
|
||||||
|
// The zone <pre> is populated on DOMContentLoaded; re-run to be safe.
|
||||||
|
await page.evaluate(() => {
|
||||||
|
const fn = (window as unknown as { renderCustMailDns?: () => void }).renderCustMailDns;
|
||||||
|
if (typeof fn === 'function') fn();
|
||||||
|
});
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
await redact(page);
|
||||||
|
const item = page.locator('#mail-client-setup').locator('xpath=ancestor::div[contains(@class,"accordion-item")]');
|
||||||
|
await item.scrollIntoViewIfNeeded();
|
||||||
|
await page.waitForTimeout(300);
|
||||||
|
const path = resolve(OUT_DIR, 'whp-email-autodiscovery.png');
|
||||||
|
await item.screenshot({ path });
|
||||||
|
console.log(`captured whp-email-autodiscovery -> ${path}`);
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => { console.error(err); process.exit(1); });
|
||||||
Reference in New Issue
Block a user