Sovite.SMTP.DataDecoder (sovite v0.2.0)

Copy Markdown View Source

Streaming decoder for SMTP DATA content (RFC 5321 §4.1.1.4, §4.5.2).

It removes dot-stuffing and finds the end of data without buffering the message: feed it bytes as they arrive and it returns the decoded content as iodata.

Only <CRLF>.<CRLF> ends the data. A bare LF or bare CR (one not part of a CRLF pair) is handled by the policy, so it can never be read as a line ending by one MTA and as content by another (SMTP smuggling):

  • :reject - stop with {:error, :bare_lf | :bare_cr}.

  • :normalize - convert it to CRLF in the output. The line it ends cannot end the data, even if it is a single dot.

The decoded content keeps CRLF line endings, and the final CRLF before the terminating dot is part of the content.

Summary

Functions

Decodes bytes.

Returns a decoder for content right after the 354 reply.

Types

policy()

@type policy() :: :reject | :normalize

t()

@opaque t()

Functions

decode(decoder, bytes)

@spec decode(t(), binary()) ::
  {:more, iodata(), t()}
  | {:done, iodata(), binary()}
  | {:error, :bare_lf | :bare_cr, iodata()}

Decodes bytes.

  • {:more, content, decoder} - the data has not ended yet.
  • {:done, content, rest} - the data ended; rest is the input after the terminating .<CRLF>, such as pipelined commands.
  • {:error, reason, content} - a bare line ending under :reject. content is what was decoded before it.

new(policy \\ :reject)

@spec new(policy()) :: t()

Returns a decoder for content right after the 354 reply.