Replace bare .body() call with .singlepart(SinglePart::plain()) to ensure
outgoing emails have explicit Content-Type: text/plain; charset=utf-8
header. This fixes recipients seeing raw quoted-printable encoding
(e.g., =E2=80=99) instead of properly decoded UTF-8 characters.
Replace unbounded HashSet<String> with a BoundedSeenSet that evicts
the oldest message IDs (FIFO) when the 100k capacity is reached. This
prevents memory growth proportional to email volume over the process
lifetime, capping the set at ~100k entries regardless of runtime.
Closes#349
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add port and host fields to GatewayConfig struct
- Add default_gateway_port() and default_gateway_host() functions
- Add apply_env_overrides() method to Config for env var support
- Fix test to include new GatewayConfig fields
All tests pass.
- WhatsApp Cloud API channel (Meta Business Platform)
- Webhook verification, text/media messages, rate limiting
- Phone number allowlist (empty=deny, *=allow, specific numbers)
- Health check via API
- Email channel (IMAP/SMTP over TLS)
- IMAP polling for inbound messages
- SMTP sending with TLS
- Sender allowlist (email, domain, wildcard)
- HTML stripping, duplicate detection
Both implement ZeroClaw's Channel trait directly.
Includes inline unit tests.