Skip to content

Add smtp_max_line_length_kb to accept non-conformant SMTP lines (fixes silent drops from e.g. Swann NVW-MR4K) - #8

Open
zutroy97 wants to merge 2 commits into
bcastellucci:mainfrom
zutroy97:feature/relaxed-smtp-line-length
Open

Add smtp_max_line_length_kb to accept non-conformant SMTP lines (fixes silent drops from e.g. Swann NVW-MR4K)#8
zutroy97 wants to merge 2 commits into
bcastellucci:mainfrom
zutroy97:feature/relaxed-smtp-line-length

Conversation

@zutroy97

@zutroy97 zutroy97 commented Sep 1, 2026

Copy link
Copy Markdown

Problem

Some SMTP senders violate RFC 2045 §6.8 by encoding a base64 attachment as a single unbroken line with no CRLF wrapping. aiosmtpd (which this add-on is built on) enforces the RFC 5321 §4.5.3.1.6 line-length limit (~1000 octets) and aborts the DATA phase with 500 Line too long the moment it hits such a line — so the add-on never receives, and therefore never publishes, any message from that sender that includes such an attachment.

I hit this with a Swann NVW-MR4K (MaxRanger4K) security hub: its motion-alert email (JPEG snapshot attached) always triggers this, 100% of the time, while its plain verification/test email (no attachment, no long line) works fine — which made it look at first like an intermittent bug rather than the hub's SMTP client having a firmware quirk with no user-facing fix.

Fix

Adds an optional smtp_max_line_length_kb config option. When set, it raises aiosmtpd's SMTP.line_length_limit for the whole listener via a small Controller/SMTP subclass built in make_relaxed_line_length_controller(). Left unset (the default), the code path is unchanged — same Controller class, same RFC-compliant 1000-octet limit as today.

Verified against:

  • A crafted message reproducing the exact malformation (a ~2.8MB single unbroken base64 line) — confirms 250 Message accepted for delivery instead of 500 Line too long, correct MIME parsing, and successful MQTT publish.
  • The real Swann hub in production — motion alerts with photos now arrive and publish correctly, where every single one silently failed before.

Second commit: fix local builds under current Supervisor

Unrelated to the line-length fix, but needed to actually build and test this: the existing Dockerfile's ARG BUILD_FROM / FROM $BUILD_FROM relies on Supervisor auto-supplying BUILD_FROM from a build.yaml — a file this repo doesn't have. Supervisor 2026.04.0+ dropped the implicit fallback that used to paper over this, so a local build of the unmodified Dockerfile now fails outright:

ERROR: failed to build: failed to solve: base name ($BUILD_FROM) should not be blank

This commit hardcodes the base image directly (FROM ghcr.io/home-assistant/base:3.24), per the current Home Assistant add-on dev docs, and adds --break-system-packages to the pip3 install, since that base image enforces PEP 668 and the bare pip3 install fails immediately after the FROM fix with an externally-managed-environment error. Anyone building this add-on locally today will hit both issues.

Compatibility

  • smtp_max_line_length_kb is optional and additive — existing installs and configs are unaffected if it's left unset.
  • Also bumped config.yaml version to 1.0.5 and updated DOCS.md/CHANGELOG.md accordingly.

Some devices (e.g. the Swann NVW-MR4K / MaxRanger4K security hub) send a
base64-encoded attachment as a single unbroken line with no CRLF wrapping,
violating RFC 2045 6.8. aiosmtpd enforces the RFC 5321 4.5.3.1.6 ~1000-octet
line limit and aborts the DATA phase with "500 Line too long" as soon as it
hits such a line, so the add-on never receives (or publishes) that message.

Adds an optional smtp_max_line_length_kb setting that raises aiosmtpd's
SMTP.line_length_limit (via a Controller/SMTP subclass built in
make_relaxed_line_length_controller) for such non-conformant senders. Left
unset, behavior is unchanged: the standard Controller class and RFC-mandated
line length limit still apply.
Supervisor 2026.04.0 stopped auto-supplying BUILD_FROM from a build.yaml
(the legacy builder file, which this add-on never actually had), so a local
build of the unmodified Dockerfile failed with:

    base name ($BUILD_FROM) should not be blank

Hardcode the base image directly in the Dockerfile instead, per current
Home Assistant add-on/app dev docs. Also add --break-system-packages to the
pip3 install, since that base image enforces PEP 668 and a bare pip install
now fails with "externally-managed-environment".

Also drop the `image:` key from config.yaml so Supervisor builds from this
Dockerfile locally instead of pulling the (unpatched) published image at
bcastellucci/image-{arch}-smtp2mqtt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant