- Snooze (with a Snoozed folder), keyboard shortcuts with a Settings section, mail templates (Compose > More > Templates), a Subscriptions folder with bulk unsubscribe/delete, and tracker blocking with a Privacy toggle (on by default) - Own dialogs instead of browser popups; emoji picker in compose; compose windows survive a visit to Settings - Sentence completion learned from the user's sent mail (no AI) - Interface in English and Polish (one file per language, English as the fallback), picked from the browser on first run, then kept - Email translation on the server via LibreTranslate: Translate button and "Translate to...", messages in several languages translated part by part, names/addresses/emoji/file names/phone numbers kept, an animated line while translating - Antispam "Mark as spam" loads with the message, not when the menu opens Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
2.0 KiB
Python
46 lines
2.0 KiB
Python
"""Tracker blocking (Settings → Privacy): on by default, and it can be switched off."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from tests.api.conftest import HDR, MailCtx, raw_mail
|
|
|
|
PIXEL = "https://t.example.com/open.gif?u=42"
|
|
HTML = f'<p>Hello</p><img src="{PIXEL}" width="1" height="1">'
|
|
|
|
|
|
async def _html(ctx: MailCtx, message_id: object, images: bool = False) -> tuple[str, str]:
|
|
resp = await ctx.client.get(
|
|
f"/api/messages/{message_id}/html", params={"images": "1"} if images else {}
|
|
)
|
|
assert resp.status_code == 200
|
|
return resp.text, resp.headers["X-Trackers-Blocked"]
|
|
|
|
|
|
async def test_trackers_blocked_by_default(mail_ctx: MailCtx) -> None:
|
|
msg = await mail_ctx.deliver(raw_mail("News", html=HTML), 1)
|
|
assert (await mail_ctx.client.get("/api/settings")).json()["block_trackers"] is True
|
|
body, count = await _html(mail_ctx, msg.id, images=True)
|
|
assert count == "1" and PIXEL not in body and "Hello" in body
|
|
(env,) = (await mail_ctx.client.get(f"/api/threads/{msg.thread_id}")).json()["messages"]
|
|
assert env["has_remote_images"] is False # nothing left worth loading
|
|
|
|
|
|
async def test_switched_off_trackers_are_ordinary_remote_images(mail_ctx: MailCtx) -> None:
|
|
msg = await mail_ctx.deliver(raw_mail("News", html=HTML), 1)
|
|
resp = await mail_ctx.client.patch("/api/settings", json={"block_trackers": False}, headers=HDR)
|
|
assert resp.json()["block_trackers"] is False
|
|
|
|
# Still a remote image: not loaded until images are allowed, but offered.
|
|
body, count = await _html(mail_ctx, msg.id)
|
|
assert count == "0" and PIXEL not in body
|
|
(env,) = (await mail_ctx.client.get(f"/api/threads/{msg.thread_id}")).json()["messages"]
|
|
assert env["has_remote_images"] is True
|
|
|
|
body, count = await _html(mail_ctx, msg.id, images=True)
|
|
assert count == "0" and PIXEL in body.replace("&", "&")
|
|
|
|
# Back on: gone again.
|
|
await mail_ctx.client.patch("/api/settings", json={"block_trackers": True}, headers=HDR)
|
|
body, count = await _html(mail_ctx, msg.id, images=True)
|
|
assert count == "1" and PIXEL not in body
|