* fix: support admin auth for Telegram MiniApp mail viewing (#852)
Admin users configured in miniAppUrl can now view emails via the
MiniApp without needing Telegram initData auth. The getMail endpoint
reads the x-admin-auth header (already sent by the frontend) to
bypass Telegram auth and address permission checks for admin users.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract isAdmin() as shared utility function
Reuse the x-admin-auth header check logic across worker.ts and
miniapp.ts via a common isAdmin() helper in utils.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: rename isAdmin to checkIsAdmin for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review comments
- Remove unused getAdminPasswords import from worker.ts
- Return 404 when admin queries a non-existent mail
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Security fix: XSS bypass via jsdom raw-text tag parsing,
prototype pollution with custom elements, and lenient config
parsing in _isValidAttribute.
Supersedes #872
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Update @playwright/test and Docker base image together to fix
CI failures caused by mismatched browser versions.
Closes#864
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
refactor: modularize IMAP server with fixes and E2E tests
- Modularize IMAP server into imap_server, imap_mailbox, imap_message,
imap_http_client, parse_email, config, models
- Support dual login: JWT token and address+password via backend
- Add STARTTLS support with configurable TLS cert/key
- Fix FETCH/STORE returning UID instead of sequence number (RFC 3501)
- Implement IMessageFile.open() for correct BODY[] raw MIME delivery
- Add UIDNEXT to SELECT response via _cbSelectWork override
- Use per-restart UIDVALIDITY to force client resync
- Pass raw MIME to SimpleMessage for accurate RFC822.SIZE
- Fix SENT mailbox returning empty source
- Handle CREATE command gracefully for Thunderbird compatibility
- Add IMAP E2E tests: auth, LIST, SELECT, STATUS, FETCH, SEARCH,
STORE, UID FETCH, BODY[] integrity, size, seq numbers, SENT mailbox
- Add SMTP E2E tests using nodemailer: send plain/HTML, auth failure,
sendbox verification
- Add sendTestMail helper using admin/send_mail
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: add receive_mail E2E endpoint using real email() handler
Add /admin/test/receive_mail that constructs a mock ForwardableEmailMessage
and calls the real email() handler, so E2E tests exercise the full mail
processing pipeline. Extract both test endpoints into e2e_test_api.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: trigger CI
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* test: add E2E tests for auto-reply settings
Add auto-reply.spec.ts with two test cases:
- GET empty → POST save → GET verify saved fields
- POST with too-long subject returns 400
Enable ENABLE_AUTO_REPLY in E2E wrangler config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add full fields and body assertion for too-long validation per review
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: correct API path typo `requset_send_mail_access` → `request_send_mail_access`
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: correct typo in send-access E2E test (requset → request)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* test: add E2E test for clearing sent items
Add clear-sent.spec.ts verifying:
- Send a mail → verify it appears in sendbox → clear sent items → verify sendbox is empty
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: remove unused address variable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* test: add E2E test for duplicate send access request
Add send-access.spec.ts verifying:
- First request succeeds and balance matches DEFAULT_SEND_BALANCE
- Duplicate request returns 400 (UNIQUE constraint)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: assert response body contains 'Already' for duplicate send access
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add mail-detail.spec.ts with two test cases:
- Fetch a seeded mail by ID and verify fields (id, address, source, raw)
- Fetch non-existent mail ID returns null
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: sanitize mail content in reply/forward to prevent XSS
- Add DOMPurify to sanitize HTML email content (whitelist-based)
- Add escapeHtml for plain text content (escape &<>"')
- Guard mail.originalSource with fallback to empty string
- Add jsdom for vitest DOM environment (DOMPurify requires DOM)
- Add XSS regression tests (script tags, event handlers, HTML escape)
- Add contentType assertion for empty message fallback case
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add XSS sanitization E2E screenshots
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove temporary screenshots from tree
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: normalize escapeHtml input and add forward text escape test
- escapeHtml: convert input via String(str ?? '') to handle non-string values
- Add test for plain text forward with special chars (<, &, >)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: preserve HTML content when replying to HTML emails (#728)
Reply was using curMail.text (plain text) instead of curMail.message (HTML),
causing loss of original email formatting. Forward already used HTML correctly.
Now reply prefers HTML content with plain text fallback, matching forward behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add vitest unit tests for reply/forward mail logic
Extract buildReplyModel and buildForwardModel into testable utility
functions and add 13 unit tests covering HTML content preservation,
plain text fallback, sender parsing, and subject formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: remove unnecessary vitest exclude config
The e2e files have been deleted, so the test.exclude config in
vite.config.js is no longer needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: revert unnecessary trailing comma in vite.config.js
Restore vite.config.js to match main exactly — no changes needed
for this PR.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add e2e screenshots for PR review
Screenshots from local Playwright test showing:
1. HTML email rendered correctly in inbox
2. Reply editor preserving HTML content in blockquote
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove temporary test screenshots
Screenshots have been posted as PR comment, no longer needed in tree.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use html contentType for HTML email replies instead of rich
wangEditor (rich text editor) strips block-level HTML tags inside
blockquote, losing all formatting. Use contentType 'html' for HTML
email replies (matching forward behavior) so content is edited as
raw HTML in a textarea, preserving all formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: update e2e screenshots showing HTML formatting preserved
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove temporary screenshots from tree
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add SMTP send flow E2E screenshots with mailpit
Screenshots showing complete SMTP HTML email reply flow:
1. View rich HTML email (gradient headers, tables, badges)
2. Reply compose with HTML mode (textarea, not wangEditor)
3. Sent box showing preserved HTML formatting
4. Mailpit inbox receiving the SMTP email
5. Mailpit email detail with full HTML rendering
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove temporary SMTP test screenshots from tree
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add Status menu button feature entry to both CN/EN changelogs
- Add missing Improvements entries to EN changelog (IP lookup link, VitePress i18n fix)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add different messages based on mail count (empty vs select)
- Add semantic icons (InboxRound for inbox, SendRound for sent)
- Unify list container height to min-height: 60vh; max-height: 100vh
- Update CHANGELOG for v1.4.0
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add OAuth2 SVG icon support (#825)
- Add async address activity update (#826)
- Add hide send mail UI when not configured (#827)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add isSendMailEnabled and isAnySendMailEnabled functions in common.ts
- Return enableSendMail field in /open_api/settings
- Hide sendmail tab, sendbox tab, and reply button when send mail is not configured
- Check RESEND_TOKEN, SMTP_CONFIG, and SEND_MAIL binding per domain
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Change updateAddressUpdatedAt to non-blocking async execution
- GET /api/mails, /api/settings, /user_api/settings no longer wait for DB update
- Improves response time for GET requests
- Also updates dependencies
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add optional `icon` field to UserOauth2Settings type
- Include preset SVG icons for GitHub, Linux Do, and Authentik templates
- Render icons on OAuth2 login buttons
- Add icon configuration UI with preview in admin panel
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(oauth2): add email format transformation support
- Add enableEmailFormat, userEmailFormat, userEmailReplace fields
- Support regex pattern matching and replacement template ($1, $2, etc.)
- Add Linux Do OAuth2 template with email format pre-configured
- Add input length limit (256 chars) to prevent ReDoS attacks
- Update admin UI with conditional display and tooltips
- Update documentation (zh/en) with configuration examples
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: update lock files and version
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: restore accessTokenFormat as optional field
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Use Gmail's #A8C7FA color for AI extraction alert and tag in dark mode
- Update CHANGELOG.md and CHANGELOG_EN.md for v1.2.1
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
fix: scheduled task cleanup error "e.get is not a function"
- Use optional chaining in i18n.getMessagesbyContext to safely access Context methods
- Update version to v1.2.1
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
ci: update PR Agent to use qodo-ai/pr-agent@main
- Add issue_comment trigger for responding to PR comments
- Add contents: write permission
- Update to official qodo-ai/pr-agent@main action
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add TG_ALLOW_USER_LANG variable to worker-vars.md (zh/en)
- Add SUBDOMAIN_FORWARD_ADDRESS_LIST with sourcePatterns docs (zh/en)
- Add /lang command and language switching docs to telegram.md (zh/en)
- Add TG_ALLOW_USER_LANG example to wrangler.toml.template
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
GitHub Container Registry requires lowercase image names. Use bash
parameter expansion to convert repository name to lowercase.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin account tab to display current login method
- Support logout for admin password login only
- Show login method (password/user admin/disabled check)
- Improve address bar responsive layout with auto-wrap
- Update changelog for new features
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>