mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-05-06 20:32:55 +08:00
* feat(mail): support gzip compressed email storage in D1 raw_blob column Add ENABLE_MAIL_GZIP env var to optionally gzip-compress incoming emails into a new raw_blob BLOB column, saving D1 storage space. Reading is backward-compatible: prioritizes raw_blob (decompress) with fallback to plaintext raw field. Includes DB migration v0.0.7, docs, and changelogs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gzip fallback on missing column + decouple resolve from handleListQuery - email/index.ts: gzip INSERT failure now falls back to plaintext INSERT instead of silently losing the email (P1: data loss prevention) - common.ts: add handleMailListQuery for raw_mails-specific list queries with resolveRawEmailList, keeping handleListQuery generic - Replace handleListQuery → handleMailListQuery in mails_api, admin_mail_api, user_mail_api (only raw_mails callers) - Add e2e test infrastructure: worker-gzip service, wrangler.toml.e2e.gzip, api-gzip playwright project, mail-gzip.spec.ts with 4 test cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review feedback for gzip feature - Use destructuring in resolveRawEmailRow to truly remove raw_blob key - Narrow fallback scope: only fallback to plaintext on compression failure or missing raw_blob column, re-throw other DB errors - Clean unused imports in e2e gzip test Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add try-catch in resolveRawEmail to prevent single corrupt blob from failing entire list A corrupted raw_blob would cause decompressBlob to throw, which with Promise.all in resolveRawEmailList would reject the entire batch query. Now catches decompression errors and falls back to row.raw field. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(mail): align sendAdminInternalMail with gzip storage path sendAdminInternalMail now respects ENABLE_MAIL_GZIP: compresses to raw_blob when enabled, with fallback to plaintext on failure. Added e2e test verifying admin internal mail is readable under gzip. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(e2e): match admin internal mail by body content instead of encoded subject mimetext base64-encodes the Subject header, so the raw MIME string does not contain the literal subject text. Match on body content (balance: 99) which is plaintext. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(e2e): add WORKER_GZIP_URL guard and length assertions in gzip tests Address CodeRabbit feedback: - Skip gzip tests when WORKER_GZIP_URL is not set to prevent false positives - Assert results array length before accessing [0] for clearer error messages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(mail): narrow gzip fallback scope and fix webhook query compatibility - sendAdminInternalMail: separate compress vs DB error handling, only fallback to plaintext on compression failure or missing raw_blob column, rethrow other DB errors (aligns with email/index.ts) - Webhook test endpoints: use SELECT * instead of explicit raw_blob column reference, so pre-migration databases don't 500 - Docs/changelog: clarify that db_migration must run before enabling ENABLE_MAIL_GZIP Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(telegram): use generic Record type for raw_mails query result Align with other query sites — avoid hardcoding raw_blob in the TypeScript type annotation so the query works with or without the column after migration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(models): add RawMailRow type and unify raw_mails query typing Add RawMailRow type to models with raw_blob as optional field, replacing ad-hoc Record<string, unknown> and inline type annotations across webhook test endpoints, telegram API, and gzip utilities. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
158 lines
3.9 KiB
YAML
158 lines
3.9 KiB
YAML
services:
|
|
mailpit:
|
|
image: axllent/mailpit:v1.29
|
|
ports:
|
|
- "1025:1025"
|
|
- "8025:8025"
|
|
|
|
worker:
|
|
build:
|
|
context: ..
|
|
dockerfile: e2e/Dockerfile.worker
|
|
ports:
|
|
- "8787:8787"
|
|
depends_on:
|
|
- mailpit
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sf", "http://localhost:8787/health_check"]
|
|
interval: 3s
|
|
timeout: 5s
|
|
start_period: 10s
|
|
retries: 20
|
|
|
|
worker-subdomain:
|
|
build:
|
|
context: ..
|
|
dockerfile: e2e/Dockerfile.worker
|
|
ports:
|
|
- "8789:8789"
|
|
command: ["pnpm", "exec", "wrangler", "dev", "--port", "8789", "--ip", "0.0.0.0"]
|
|
depends_on:
|
|
- mailpit
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sf", "http://localhost:8789/health_check"]
|
|
interval: 3s
|
|
timeout: 5s
|
|
start_period: 10s
|
|
retries: 20
|
|
|
|
worker-env-off:
|
|
build:
|
|
context: ..
|
|
dockerfile: e2e/Dockerfile.worker
|
|
ports:
|
|
- "8790:8790"
|
|
command: ["pnpm", "exec", "wrangler", "dev", "--port", "8790", "--ip", "0.0.0.0"]
|
|
volumes:
|
|
- ./fixtures/wrangler.toml.e2e.env-off:/app/worker/wrangler.toml:ro
|
|
depends_on:
|
|
- mailpit
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sf", "http://localhost:8790/health_check"]
|
|
interval: 3s
|
|
timeout: 5s
|
|
start_period: 10s
|
|
retries: 20
|
|
|
|
worker-gzip:
|
|
build:
|
|
context: ..
|
|
dockerfile: e2e/Dockerfile.worker
|
|
args:
|
|
WRANGLER_TOML: e2e/fixtures/wrangler.toml.e2e.gzip
|
|
ports:
|
|
- "8788:8788"
|
|
command: ["pnpm", "exec", "wrangler", "dev", "--port", "8788", "--ip", "0.0.0.0"]
|
|
depends_on:
|
|
- mailpit
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sf", "http://localhost:8788/health_check"]
|
|
interval: 3s
|
|
timeout: 5s
|
|
start_period: 10s
|
|
retries: 20
|
|
|
|
frontend:
|
|
build:
|
|
context: ..
|
|
dockerfile: e2e/Dockerfile.frontend
|
|
ports:
|
|
- "5173:5173"
|
|
depends_on:
|
|
worker:
|
|
condition: service_healthy
|
|
|
|
smtp-proxy:
|
|
build:
|
|
context: ../smtp_proxy_server
|
|
dockerfile: dockerfile
|
|
ports:
|
|
- "11025:8025"
|
|
- "11143:11143"
|
|
environment:
|
|
PROXY_URL: http://worker:8787
|
|
PORT: "8025"
|
|
IMAP_PORT: "11143"
|
|
depends_on:
|
|
worker:
|
|
condition: service_healthy
|
|
|
|
smtp-proxy-tls:
|
|
build:
|
|
context: ../smtp_proxy_server
|
|
dockerfile: dockerfile
|
|
ports:
|
|
- "11026:8026"
|
|
- "11144:11144"
|
|
environment:
|
|
PROXY_URL: http://worker:8787
|
|
PORT: "8026"
|
|
IMAP_PORT: "11144"
|
|
smtp_tls_cert: /certs/cert.pem
|
|
smtp_tls_key: /certs/key.pem
|
|
imap_tls_cert: /certs/cert.pem
|
|
imap_tls_key: /certs/key.pem
|
|
entrypoint: ["/bin/bash", "/e2e-scripts/smtp-tls-entrypoint.sh"]
|
|
volumes:
|
|
- ./scripts:/e2e-scripts:ro
|
|
depends_on:
|
|
worker:
|
|
condition: service_healthy
|
|
|
|
e2e-runner:
|
|
build:
|
|
context: ..
|
|
dockerfile: e2e/Dockerfile.e2e
|
|
environment:
|
|
WORKER_URL: http://worker:8787
|
|
WORKER_URL_SUBDOMAIN: http://worker-subdomain:8789
|
|
WORKER_URL_ENV_OFF: http://worker-env-off:8790
|
|
WORKER_GZIP_URL: http://worker-gzip:8788
|
|
FRONTEND_URL: https://frontend:5173
|
|
MAILPIT_API: http://mailpit:8025/api
|
|
SMTP_PROXY_HOST: smtp-proxy
|
|
SMTP_PROXY_SMTP_PORT: "8025"
|
|
SMTP_PROXY_IMAP_PORT: "11143"
|
|
SMTP_PROXY_TLS_HOST: smtp-proxy-tls
|
|
SMTP_PROXY_TLS_SMTP_PORT: "8026"
|
|
SMTP_PROXY_TLS_IMAP_PORT: "11144"
|
|
CI: "true"
|
|
depends_on:
|
|
worker:
|
|
condition: service_healthy
|
|
worker-subdomain:
|
|
condition: service_healthy
|
|
worker-env-off:
|
|
condition: service_healthy
|
|
worker-gzip:
|
|
condition: service_healthy
|
|
frontend:
|
|
condition: service_started
|
|
smtp-proxy:
|
|
condition: service_started
|
|
smtp-proxy-tls:
|
|
condition: service_started
|
|
volumes:
|
|
- ./test-results:/app/e2e/test-results
|
|
- ./playwright-report:/app/e2e/playwright-report
|