Compare commits
4
Commits
6700ce27b8
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8eca7f09f | ||
|
|
2044d9e0bc | ||
|
|
0366e864f8 | ||
|
|
9f30b6a2b3 |
Binary file not shown.
|
After Width: | Height: | Size: 182 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
title: Release or allow quarantined email
|
||||||
|
description: Get a message out of spam quarantine yourself, right away — no need to wait for the daily notice.
|
||||||
|
sidebar:
|
||||||
|
order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
import { Steps, Aside } from '@astrojs/starlight/components';
|
||||||
|
import Support from '~/content/partials/support-link.mdx';
|
||||||
|
|
||||||
|
Mail our filters flag as likely spam isn't delivered to your inbox — it's held in **quarantine** instead, where you can review it, release anything that's actually wanted, and always allow a sender in future. You don't have to wait for the daily notice to do this — see below.
|
||||||
|
|
||||||
|
## Check your quarantine
|
||||||
|
|
||||||
|
You'll normally get a **daily summary email** listing anything held for you — but the steps below work any time, not just after that email arrives. There's no separate password to remember; a link emailed to your own address is what signs you in.
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
|
||||||
|
1. Go to your mail filtering portal at `https://pmg01.cloud-hosting.io:8006/quarantine`. Choose **Request Quarantine Link**.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
2. Enter the email address you want to check.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
3. Open the email that arrives — usually within moments — and follow the link inside it.
|
||||||
|
|
||||||
|
4. Review what's listed for your address.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
5. Select a message to see its content and the Whitelist / Blacklist / Deliver / Delete options, then choose **Deliver** to send it to your inbox as normal.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
<Aside type="tip">
|
||||||
|
**Need something released right now?** This works any time of day, not just once daily — request a new link as often as you need one. No need to wait for the daily summary email.
|
||||||
|
</Aside>
|
||||||
|
|
||||||
|
## Always allow a sender
|
||||||
|
|
||||||
|
If mail from someone keeps getting caught and you know it's legitimate, allow their address (or their whole domain) from the same screen — choose **Whitelist** on a held message (shown in the screenshot above), or add the address directly from the quarantine portal. Future mail from that sender skips spam filtering for **your address specifically** — it doesn't change anything for the rest of your organization.
|
||||||
|
|
||||||
|
<Aside type="caution">
|
||||||
|
Only allow senders you actually recognize. Allowing an address skips spam checks for it entirely, so it's worth being deliberate rather than allowing everything that shows up.
|
||||||
|
</Aside>
|
||||||
|
|
||||||
|
## Common problems
|
||||||
|
|
||||||
|
**The sign-in link email hasn't arrived.** Check your spam folder — slightly ironic for a spam-filtering tool, but it happens. If it's still missing after a few minutes, contact us.
|
||||||
|
|
||||||
|
**I can't find a message I expected.** Quarantine holds mail for a limited time before it's cleared automatically, so check soon after being notified rather than weeks later. If it's genuinely missing, contact us and we can check on our end.
|
||||||
|
|
||||||
|
**A sender I allowed is still landing in quarantine.** Double check you allowed the exact address (or domain) it actually sends from — some services send from a different address than the one they display, especially automated notifications.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [Changes to spam filtering](/email/spam-filtering-changes/)
|
||||||
|
- [Set up your email](/email/set-up-your-email-client/)
|
||||||
|
|
||||||
|
## Still stuck?
|
||||||
|
|
||||||
|
<Support />
|
||||||
@@ -45,6 +45,7 @@ We'll update this page as the migration progresses.
|
|||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
|
- [Release or allow quarantined email](/email/release-quarantined-email/)
|
||||||
- [Set up your email](/email/set-up-your-email-client/)
|
- [Set up your email](/email/set-up-your-email-client/)
|
||||||
- [Create an email account](/whp/how-to/create-an-email-account/)
|
- [Create an email account](/whp/how-to/create-an-email-account/)
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ npx tsx tools/screenshots/capture-dns.ts
|
|||||||
| `capture-site-builder.ts` | Site Builder editor states | `WHP_USER` |
|
| `capture-site-builder.ts` | Site Builder editor states | `WHP_USER` |
|
||||||
| `capture-dns.ts` | Domains & DNS list, Add Domain modal, records editor, bulk toolbar | `WHP_USER` |
|
| `capture-dns.ts` | Domains & DNS list, Add Domain modal, records editor, bulk toolbar | `WHP_USER` |
|
||||||
| `capture-email.ts` | Email page "Mail Client Setup" section (autodiscovery DNS records) | `WHP_USER` |
|
| `capture-email.ts` | Email page "Mail Client Setup" section (autodiscovery DNS records) | `WHP_USER` |
|
||||||
|
| `capture-quarantine.ts` | PMG spam quarantine portal (login, request-link dialog, held-mail list, message actions) — **not a WHP page**, targets the mail filtering gateway directly | `PMG_BASE` + `PMG_TICKET_URL` (a real quarantine ticket link, e.g. from a test mailbox's "Request Quarantine Link" email) instead of WHP_USER/PASS |
|
||||||
|
|
||||||
Each script carries its own `redact()` (text-node + input-value swaps) so fleet hostnames, IPs, and customer data become neutral placeholders while brand/demo domains stay visible. Copy the closest existing script when adding a new section — match its viewport (1440×900), `deviceScaleFactor: 2`, and **read-only** discipline (open modals and tick boxes for the shot, but never save/delete/submit).
|
Each script carries its own `redact()` (text-node + input-value swaps) so fleet hostnames, IPs, and customer data become neutral placeholders while brand/demo domains stay visible. Copy the closest existing script when adding a new section — match its viewport (1440×900), `deviceScaleFactor: 2`, and **read-only** discipline (open modals and tick boxes for the shot, but never save/delete/submit).
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* PMG quarantine capture — the customer self-service spam quarantine portal.
|
||||||
|
*
|
||||||
|
* Captures:
|
||||||
|
* - email-quarantine-login.png Login screen showing the "Request Quarantine
|
||||||
|
* Link" button next to Login.
|
||||||
|
* - email-quarantine-request.png The "Request Quarantine Link" dialog with an
|
||||||
|
* email address entered.
|
||||||
|
* - email-quarantine-list.png The authenticated quarantine grid showing held
|
||||||
|
* mail, redacted to generic example content.
|
||||||
|
* - email-quarantine-actions.png A selected message with the Whitelist /
|
||||||
|
* Blacklist / Deliver / Delete toolbar visible.
|
||||||
|
*
|
||||||
|
* Viewport-only (1440x900, deviceScaleFactor 2), redacted: the real server
|
||||||
|
* hostname, the real test mailbox address, and the real (internal-test-looking)
|
||||||
|
* sender/subject/body text are all swapped for generic customer-facing examples.
|
||||||
|
*
|
||||||
|
* Read-only: never actually delivers/whitelists/blacklists/deletes anything.
|
||||||
|
*/
|
||||||
|
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/email');
|
||||||
|
|
||||||
|
const BASE = process.env.PMG_BASE || 'https://pmg01.cloud-hosting.io:8006';
|
||||||
|
const TICKET_URL = process.env.PMG_TICKET_URL; // full quarantine?ticket=... URL
|
||||||
|
|
||||||
|
/** Swap real fleet/test identifiers for believable generic customer-facing text. */
|
||||||
|
async function redact(page: Page) {
|
||||||
|
await page.evaluate(() => {
|
||||||
|
const swaps: [RegExp, string][] = [
|
||||||
|
[/pmg01\.cloud-hosting\.io/gi, 'mail.yourdomain.com'],
|
||||||
|
[/claude@darksideofperfection\.com/gi, 'you@yourdomain.com'],
|
||||||
|
[/pmg-pilot-tester@anthropic\.com/gi, 'prizes@totally-legit-sweepstakes.example'],
|
||||||
|
[/SPAM: PMG pilot - spam detection test \(GTUBE\) \(retry\)/g, "SPAM: You've WON a prize!!!"],
|
||||||
|
[/SPAM: PMG pilot - clean delivery test \(retry\)/g, 'SPAM: Limited time offer - act now'],
|
||||||
|
[/This is a clean end-to-end delivery test, retried after greylist window\./g,
|
||||||
|
'Congratulations! You have been selected to receive an exclusive reward. Click below to claim yours before this offer expires.'],
|
||||||
|
[/GTUBE retry test\./g, "You've been selected for an exclusive reward!"],
|
||||||
|
[/XJS\*C4JDBQADN1\.NSBN3\*2IDNEN\*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL\*C\.34X/g,
|
||||||
|
'Click here to claim your prize before this limited-time offer expires: http://totally-legit-sweepstakes.example/claim'],
|
||||||
|
[/\b1010\b/g, '8.4'],
|
||||||
|
];
|
||||||
|
const docs: Document[] = [document];
|
||||||
|
for (const f of Array.from(document.querySelectorAll('iframe'))) {
|
||||||
|
try {
|
||||||
|
const doc = (f as HTMLIFrameElement).contentDocument;
|
||||||
|
if (doc) docs.push(doc);
|
||||||
|
} catch { /* cross-origin, skip */ }
|
||||||
|
}
|
||||||
|
for (const root of docs) {
|
||||||
|
const walker = root.createTreeWalker(root.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() {
|
||||||
|
if (!TICKET_URL) throw new Error('missing env: PMG_TICKET_URL');
|
||||||
|
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 {
|
||||||
|
// --- Shot 1: login screen, showing the Request Quarantine Link button ---
|
||||||
|
await page.goto(`${BASE}/quarantine`, { waitUntil: 'networkidle' });
|
||||||
|
await page.waitForSelector('text=Request Quarantine Link', { state: 'visible' });
|
||||||
|
await page.waitForTimeout(300);
|
||||||
|
await redact(page);
|
||||||
|
let p = resolve(OUT_DIR, 'email-quarantine-login.png');
|
||||||
|
await page.locator('.x-window').first().screenshot({ path: p });
|
||||||
|
console.log(`captured email-quarantine-login -> ${p}`);
|
||||||
|
|
||||||
|
// --- Shot 2: the Request Quarantine Link dialog, filled in ---
|
||||||
|
await page.getByRole('button', { name: 'Request Quarantine Link' }).click();
|
||||||
|
await page.getByRole('textbox', { name: 'Your E-Mail:' }).fill('you@yourdomain.com');
|
||||||
|
await page.waitForTimeout(200);
|
||||||
|
p = resolve(OUT_DIR, 'email-quarantine-request.png');
|
||||||
|
await page.locator('.x-window').last().screenshot({ path: p });
|
||||||
|
console.log(`captured email-quarantine-request -> ${p}`);
|
||||||
|
|
||||||
|
// --- Shot 3 & 4: authenticated quarantine view, via the real ticket link ---
|
||||||
|
await page.goto(TICKET_URL, { waitUntil: 'networkidle' });
|
||||||
|
await page.waitForSelector('grid[aria-label="Spam Quarantine"], .x-grid', { state: 'visible' }).catch(() => {});
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await redact(page);
|
||||||
|
p = resolve(OUT_DIR, 'email-quarantine-list.png');
|
||||||
|
await page.screenshot({ path: p });
|
||||||
|
console.log(`captured email-quarantine-list -> ${p}`);
|
||||||
|
|
||||||
|
// Select the first row to reveal the action toolbar + message preview.
|
||||||
|
const firstRow = page.locator('.x-grid-row').first();
|
||||||
|
await firstRow.click();
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await redact(page);
|
||||||
|
p = resolve(OUT_DIR, 'email-quarantine-actions.png');
|
||||||
|
await page.screenshot({ path: p });
|
||||||
|
console.log(`captured email-quarantine-actions -> ${p}`);
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => { console.error(err); process.exit(1); });
|
||||||
Reference in New Issue
Block a user