smtp

package
v0.331.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 21, 2026 License: AGPL-3.0 Imports: 4 Imported by: 0

Documentation

Overview

Package smtp decodes SMTP (Simple Mail Transfer Protocol) messages per RFC 5321 — the 40-year-old text-based protocol every mail server speaks. Default ports: TCP/25 (mail exchange between MTAs), TCP/587 (mail submission with STARTTLS), TCP/465 (implicit-TLS submission, "SMTPS").

Operationally, SMTP is the canonical text protocol on the boundary between MTAs (Exim, Postfix, Sendmail, Exchange, Office 365 Exchange Online, Google Workspace, Mailcow, Mailgun, SendGrid). It is interesting to a mail-server pentester for:

  • **Open-relay testing** — the classic `MAIL FROM: <attacker@evil.com>` + `RCPT TO:<victim@target.com>` sequence detects whether a server accepts mail for non-local recipients (open relay = spam abuse risk).
  • **User enumeration** — `VRFY user` returns 250 if the mailbox exists, 550 if not; `EXPN list` expands mailing-list members; `RCPT TO:<user@target>` is a fallback when VRFY is disabled. All three are commonly used to enumerate valid usernames from a mail server.
  • **STARTTLS downgrade audit** — a server's response to `EHLO` lists `STARTTLS` if it supports opportunistic TLS; clients that don't enforce TLS can be downgraded.
  • **Authentication enumeration** — `AUTH` listing in EHLO reveals supported SASL mechanisms (LOGIN / PLAIN / CRAM-MD5 / DIGEST-MD5 / SCRAM-SHA-1 / SCRAM-SHA-256 / XOAUTH2 / GSSAPI).
  • **Banner fingerprinting** — the 220 banner on connect leaks MTA software + version (e.g. `220 mail.example.com ESMTP Postfix (Debian/GNU)`).
  • **DEF CON / HITB / CTF challenges** — open-relay + UCEPROTECT-list + DKIM/DMARC alignment puzzles frequently use SMTP captures.

Wrap-vs-native judgement

Native. RFC 5321 is publicly available; SMTP is a tiny
text-based protocol — two message kinds (Client Command
and Server Response), CRLF-terminated lines, a fixed
verb registry, and a 3-digit status code scheme. The
multi-line response format (RFC 5321 §4.2.1) uses
`<code>-<text>` for intermediate lines and `<code>
<text>` for the final line of a multi-line reply; the
decoder aggregates these. No crypto at the parse layer
(STARTTLS triggers a TLS upgrade — handle the post-
STARTTLS bytes through a TLS strip first).

What this package covers

  • **Two message kinds** discriminated by the first character of the first line:

  • **Server Response** — first line starts with a 3- digit ASCII status code (`220 mail.example.com ESMTP Postfix\r\n`). Multi-line responses use `<code>-<text>` for intermediate lines and `<code> <text>` (space, not hyphen) for the final line — the decoder aggregates all lines into a single `lines` slice + a `final_line_text` field.

  • **Client Command** — first line starts with an ASCII letter (`HELO mail.example.com\r\n`). The decoder splits the first whitespace-delimited token as the verb + the remainder as the argument.

  • **14+ entry Verb name table** (RFC 5321 §4.1.1 + RFC 1869 EHLO + RFC 1652 8BITMIME + RFC 3030 BDAT + RFC 4954 AUTH + RFC 3207 STARTTLS): `HELO` (legacy greeting — single-line response) / `EHLO` (extended greeting — multi-line response listing supported extensions) / `AUTH` (SASL authentication — followed by mechanism + base64 initial response) / `MAIL` (from-address, prefix `MAIL FROM:`) / `RCPT` (to-address, prefix `RCPT TO:`) / `DATA` (begin message body; server replies 354 then expects CRLF.CRLF terminator) / `RSET` (abort current transaction) / `VRFY` (verify mailbox exists — user enumeration target) / `EXPN` (expand mailing list — user enumeration target) / `QUIT` (close session) / `STARTTLS` (upgrade to TLS — RFC 3207) / `HELP` / `NOOP` / `BDAT` (binary data chunking per RFC 3030).

  • **HTTP-style status code categorisation**: 2xx `Success` (220 banner / 221 closing / 250 OK / 251 forward) / 3xx `Intermediate` (354 start mail input — only DATA gets this) / 4xx `Transient_Error` (421 service unavailable / 450 mailbox busy / 451 local processing error / 452 insufficient storage) / 5xx `Permanent_Error` (500 syntax / 501 parameters / 502 not implemented / 503 bad sequence / 504 unrecognised parameter / 535 authentication failed / 550 mailbox unavailable / 553 mailbox name not allowed / 554 transaction failed). The decoder surfaces this as `status_category` on the response.

  • **Multi-line response aggregation** — server replies to EHLO frequently span 5+ lines (one per extension). The decoder walks the entire input collecting every line that shares the same status code, exposes the full list as `lines`, and identifies the final line (space-after-code) as `final_line_text` for caller convenience.

  • **EHLO extension list** — when the server responds to EHLO with a multi-line reply, every line after the first contains a supported extension keyword (`SIZE 35882577` / `8BITMIME` / `STARTTLS` / `AUTH LOGIN PLAIN` / `ENHANCEDSTATUSCODES` / etc.). The decoder surfaces these as `ehlo_extensions` on response messages where the code is 250 + line count > 1.

What this package does NOT cover (deliberately out of scope)

  • **Network framing** — feed SMTP bytes after the TCP- segment header strip (default TCP port 25 / 587 / 465).
  • **STARTTLS / SMTPS transport** — after a successful STARTTLS handshake the connection upgrades to TLS; handle the TLS strip first before feeding the decrypted bytes back.
  • **MIME / mail body parsing** — the bytes between `354` server reply and the `\r\n.\r\n` terminator are the RFC 5322 mail body (with optional MIME structure per RFC 2045); separate decoder.
  • **SASL mechanism decoding** — AUTH command arguments are SASL mechanism + optional initial response (base64-encoded); the decoder surfaces them as raw strings; per-mechanism decoding (PLAIN → username + password; CRAM-MD5 → challenge + HMAC response; SCRAM-SHA-1 → 5-message exchange) is out of scope.
  • **DKIM / DMARC / SPF** — DNS-side anti-spam machinery; SMTP carries DKIM-Signature in the body header, but parsing the signature + validating against the DNS TXT record is a separate concern.
  • **Submission queue + bounce handling** — Postfix / Sendmail queue semantics, bounce-message generation, forwarding loop detection are all higher-level.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type MessageKind

type MessageKind string

MessageKind enumerates the two SMTP message kinds.

const (
	KindCommand  MessageKind = "Command"
	KindResponse MessageKind = "Response"
	KindUnknown  MessageKind = "uncatalogued"
)

type Result

type Result struct {
	TotalBytes int         `json:"total_bytes"`
	Kind       MessageKind `json:"kind"`

	// Command only.
	Verb     string `json:"verb,omitempty"`
	Argument string `json:"argument,omitempty"`

	// Response only.
	StatusCode     int      `json:"status_code,omitempty"`
	StatusCategory string   `json:"status_category,omitempty"`
	Lines          []string `json:"lines,omitempty"`
	FinalLineText  string   `json:"final_line_text,omitempty"`
	EHLOExtensions []string `json:"ehlo_extensions,omitempty"`
}

Result is the structured decode of an SMTP message.

func Decode

func Decode(hexStr string) (*Result, error)

Decode parses an SMTP message from a hex string. Separators (':' '-' '_' whitespace) tolerated; '0x' prefix tolerated.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL