LemonChannels. Adapters. Email. Attachments
(lemon_channels v0.1.0)
View Source
Persists inbound email attachments to disk and describes them for the agent.
Shape of the work
prepare/1 runs on the request path and is deliberately cheap: it decides a
target path, sanitizes the filename and applies the size cap, but writes
nothing. It returns metadata plus a list of write thunks, and schedule/1
runs those in a background task. The provider's webhook therefore gets its
response back without waiting on file I/O, while the path in the metadata is
already valid — the run that reads it is queued behind scheduling and
engine startup, which is the buffer this relies on.
What is refused
An attachment over the cap is dropped with a warning rather than truncated.
The cap defaults to three quarters of LemonChannels.InboundHttp.max_body_bytes/0
rather than to a number of its own, because the two limits are not
independent: an attachment arrives base64-encoded, taking about a third more
space on the wire than decoded, so anything larger than that fraction of the
body limit is unreachable — the request is rejected with a 413 before this
code ever sees it. Deriving it means raising the body limit raises the
attachment cap with it, and a cap that promises more than the listener will
accept cannot be configured by accident. Override deliberately with:
config :lemon_channels, LemonChannels.Adapters.Email, attachment_max_bytes: nFilenames are reduced to their basename with everything outside
[A-Za-z0-9._-] replaced — an attachment name is attacker-controlled, and it
is about to become a path. Written files are chmod 0600 on Unix, since they
can contain anything someone chose to mail an agent.
Attachments that are only a URL are passed through undownloaded: fetching a remote URL named by an unauthenticated sender is a request forgery this adapter should not make on its own.
Summary
Functions
One human-readable line per attachment, for the prompt the agent sees.
Splits raw attachments into metadata and deferred writes.
Runs deferred writes off the request path. Always returns :ok.
Types
@type meta() :: %{ filename: binary(), content_type: binary() | nil, path: binary() | nil, url: binary() | nil, bytes: non_neg_integer() | nil }
Functions
One human-readable line per attachment, for the prompt the agent sees.
Splits raw attachments into metadata and deferred writes.
Anything unrecognized, oversized or empty is dropped, so the returned lists can be shorter than the input.
@spec schedule([(-> any())]) :: :ok
Runs deferred writes off the request path. Always returns :ok.