Sign in

    mbt-email

    An RFC 5322/2045 email address and MIME message parser written in pure MoonBit. Supports email address validation, MIME multipart parsing, and message serialization.

    email
    mime
    parser
    rfc5322
    rfc2045
    Download zip
    Author
    Version
    0.1.0
    License
    MIT
    Last updated
    2 months ago
    Downloads
    16

    #mbt-email

    An RFC 5322/2045 email address and MIME message parser written in pure MoonBit.

    mbt-email parses raw email text into a structured MoonBit AST (built on algebraic data types) and serializes it back into standards-compliant text, providing foundational email-protocol handling for the MoonBit ecosystem.

    #Features

    • RFC 5322 email address parsing: dot-atom, quoted-string, domain-literal, and display-name mailboxes (Alice <alice@example.com>)
    • RFC 5322 message headers: From, To, Cc, Subject, Date, Message-ID, Received, References, In-Reply-To, etc.
    • RFC 2045/2046 MIME parsing: multipart/mixed, multipart/alternative, multipart/related, recursive nested part trees
    • Content-Type / Content-Disposition parsing: media type, subtype, and parameters (charset, boundary, name, filename)
    • RFC 2047 encoded-word decoding: =?UTF-8?B?base64?= → decoded text
    • RFC 2231 extended parameters: filename*0* continuation merging and percent-decoding
    • Transfer codecs: Base64 and Quoted-Printable (encode + decode)
    • Date handling: RFC 5322 date-time parsing, validation, timestamp conversion
    • Parse to AST: parse() / parse_mime() convert raw email text into a Message
    • Serialize back: to_string() converts AST back to RFC-compliant text
    • Build helpers: construct text / HTML / multipart / attachment messages
    • Zero external dependencies: pure MoonBit, no third-party packages

    #Installation

    #From mooncakes.io

    moon add Mr-Houjie/mbt-email

    Then import the package in your moon.pkg:

    ///|
    let msg = @Mr-Houjie/mbt-email.parse(input)

    #From source

    git clone https://github.com/Mr-Houjie/mbt-email.git cd mbt-email moon build

    #Usage

    #Parse an email message

    ///|
    let input = "From: alice@example.com\r\n" +
    "To: bob@example.com\r\n" +
    "Subject: Hello\r\n" +
    "\r\n" +
    "Hello, world!\r\n"

    ///|
    let msg = @Mr-Houjie/mbt-email.parse(input)

    #Access headers

    ///|
    let from = @Mr-Houjie/mbt-email.get_header(msg, "From")

    ///|
    let subject = @Mr-Houjie/mbt-email.message_subject(msg)

    #Parse email addresses

    ///|
    let addrs = @Mr-Houjie/mbt-email.parse_address_list(
    "Alice <a@example.com>, Bob <b@example.com>",
    )

    #Parse a MIME message with attachments

    ///|
    let msg = @Mr-Houjie/mbt-email.parse_mime(input)

    #Serialize back to RFC text

    ///|
    let text = @Mr-Houjie/mbt-email.to_string(msg)

    #CLI

    moon run cmd/main

    The CLI parses a demo email and prints parsed headers, addresses, body, and the round-trip serialization.

    #API reference

    All entry points are in the top-level @Mr-Houjie/mbt-email package.

    #Entry points

    FunctionDescription
    parse(input)Parse raw email text into a Message
    parse_mime(input)Parse a MIME message with full multipart support
    to_string(msg)Serialize a Message back to RFC 5322 text

    #Addresses

    FunctionDescription
    parse_address(input)Parse a single user@domain address
    parse_address_list(input)Parse a comma-separated address list
    parse_mailbox(input)Parse a mailbox with optional display name
    parse_mailbox_list(input)Parse a mailbox list
    validate_email_address(addr) / validate_domain / validate_local_partValidate address components
    address_to_string / mailbox_to_stringFormat back to text

    #MIME

    FunctionDescription
    parse_content_type(value)Parse a Content-Type header value
    parse_content_disposition(value)Parse a Content-Disposition value
    collect_attachments(part)Collect attachment MIME parts
    part_filename(part)Extract the filename of a part
    plain_text(part)Extract plain text from a MIME tree
    message_content_type / message_boundaryRead a message's MIME info

    #Headers & encoding

    FunctionDescription
    decode_header_value(input)Decode RFC 2047 encoded-words in a header
    decode_encoded_word(input)Decode a single encoded-word
    decode_rfc2231_value / merge_extended_paramsDecode RFC 2231 parameters
    get_header / get_headers / has_headerLook up headers (case-insensitive)

    #Dates & misc

    FunctionDescription
    parse_email_date(input)Parse an RFC 5322 date-time
    email_date_to_string / format_rfc5322_dateFormat a date
    to_timestamp / compare_datesDate conversions
    b64_encode_text / b64_decode_text / qp_encode_text / qp_decodeTransfer codecs
    message_subject / message_from_mailboxes / message_cc_mailboxesMessage-level helpers
    make_text_message / make_html_message / make_multipart_messageBuild messages

    #Project structure

    mbt-email/ ├── lexer.mbt # Tokenizer (RFC 5322 / MIME tokens) ├── parser.mbt # Recursive-descent parser ├── ast.mbt # AST types (EmailAddress, Header, MimePart, Message) ├── serializer.mbt # AST → RFC 5322 text ├── address.mbt # Address & mailbox parsing ├── header.mbt # Header value decoding (RFC 2047 / 2231) ├── mime.mbt # Recursive multipart MIME parsing ├── codec.mbt # Base64 / Quoted-Printable codecs ├── datetime.mbt # RFC 5322 date-time ├── message.mbt # Message-level helpers ├── build.mbt # Message construction & serialization ├── utils.mbt # Utilities (UTF-8, HTML escaping, URL encoding) └── cmd/main/ # CLI example

    #Building

    moon build

    #Testing

    moon test

    #License

    AddressGroup

    pub struct AddressGroup {
    name : String
    members : Array[EmailAddress]
    }

    An address group: GroupName: member1, member2;

    Body

    pub enum Body {
    Text(String)
    Binary(Bytes)
    Multipart(Array[MimePart])
    }

    A MIME body part.

    ContentDisposition

    pub struct ContentDisposition {
    disposition : String
    params : Array[(String, String)]
    }

    A MIME content-disposition (inline or attachment).

    ContentType

    pub struct ContentType {
    media_type : String
    sub_type : String
    params : Array[(String, String)]
    }

    A MIME content-type with media type, subtype, and parameters.

    EmailAddress

    pub struct EmailAddress {
    local_part : String
    domain : String
    }

    A parsed email address: local-part@domain

    EmailDate

    pub struct EmailDate {
    year : Int
    month : Int
    day : Int
    hour : Int
    minute : Int
    second : Int
    tz_hour : Int
    tz_minute : Int
    tz_sign : Int
    }

    A structured RFC 5322 date-time value. Represents the components of a date header after parsing.
    pub struct Header {
    name : String
    value : String
    }

    An email header: name and raw value.

    Mailbox

    pub struct Mailbox {
    display_name : String
    address : EmailAddress?
    }

    A mailbox: optional display name plus the addr-spec.

    Message

    pub struct Message {
    headers : Array[Header]
    body : String?
    mime_part : MimePart?
    }

    A parsed email message with headers and optional MIME body.

    MessageId

    pub struct MessageId {
    id : String
    domain : String
    }

    A parsed Message-ID header value: id@domain

    MimePart

    pub struct MimePart {
    headers : Array[Header]
    body : Body
    }

    A MIME part: headers + body.

    ReceivedInfo

    pub struct ReceivedInfo {
    from_ : String
    by : String
    with_ : String
    for_ : String
    date : String
    }

    A structured Received header value. Received: from a by b with c for d; date

    Token

    pub enum Token {
    HeaderName(String)
    HeaderValue(String)
    AtSign
    Dot
    Comma
    Semicolon
    Colon
    Equals
    LAngle
    RAngle
    RBracket
    LParen
    RParen
    Slash
    QuotedString(String)
    Atom(String)
    DomainLiteral(String)
    Newline
    EOF
    Boundary(String)
    }

    Token types for email/MIME lexing.

    address_group

    fn address_group(name~ : String, members~ : Array[EmailAddress]) -> AddressGroup

    Create an AddressGroup value.

    address_to_string

    fn address_to_string(addr : EmailAddress) -> String

    Serialize an EmailAddress to string.

    all_headers

    fn all_headers(msg : Message, name : String) -> Array[Header]

    Get all header values with a name, as a single array.

    attachment_part

    fn attachment_part(body~ : Bytes, filename~ : String, mime_type? : String) -> MimePart

    Create a new attachment MIME part.

    b64_decode_bytes

    fn b64_decode_bytes(input : String) -> Array[Int]?

    Decode a Base64 string into a byte sequence. Returns None if the input is not valid Base64.

    b64_decode_text

    fn b64_decode_text(input : String) -> String?

    Decode a Base64 string into a text string (Latin-1 mapping).

    b64_encode_bytes

    fn b64_encode_bytes(data : Array[Int]) -> String

    Encode a byte sequence as Base64, with 76-character line wrapping.

    b64_encode_text

    fn b64_encode_text(s : String) -> String

    Encode a text string as Base64 using Latin-1 mapping.

    build_message

    fn build_message(headers : Array[(String, String)], body : String) -> Message

    Build a Message from header name/value pairs and a body.

    canonical_charset

    fn canonical_charset(name : String) -> String

    Convert a charset name to a canonical lowercase form.

    collapse_ws

    fn collapse_ws(s : String) -> String

    Collapse runs of whitespace into single spaces.

    collect_attachments

    fn collect_attachments(part : MimePart) -> Array[MimePart]

    Collect all attachments from a MIME part tree.

    compare_dates

    fn compare_dates(a : EmailDate, b : EmailDate) -> Int

    Compare two EmailDates: returns -1, 0, or 1 based on their timestamps.

    content_type_param

    fn content_type_param(ct : ContentType, name : String) -> String?

    Look up a parameter value by name in a ContentType.

    content_type_to_string

    fn content_type_to_string(ct : ContentType) -> String

    Convert a ContentType into a header value string.

    count_encoded_words

    fn count_encoded_words(input : String) -> Int

    Count the number of encoded-words in a header value.

    days_in_month

    fn days_in_month(year : Int, month : Int) -> Int

    Get the number of days in a given month, accounting for leap years.

    decode_content_disposition

    fn decode_content_disposition(value : String) -> ContentDisposition?

    Decode a Content-Disposition header with RFC 2231 extended parameters.

    decode_content_type

    fn decode_content_type(value : String) -> ContentType?

    Decode a Content-Type header with RFC 2231 extended parameters.

    decode_encoded_word

    fn decode_encoded_word(input : String) -> String?

    Decode an RFC 2047 encoded-word. Format: =?charset?encoding?encoded_text?=

    decode_header_value

    fn decode_header_value(input : String) -> String

    Decode all RFC 2047 encoded-words in a header value.

    Adjacent encoded-words are concatenated without a separator, while a regular space between encoded-words is collapsed. Non-encoded text is passed through unchanged.

    decode_rfc2231_value

    fn decode_rfc2231_value(input : String) -> String?

    Decode a single RFC 2231 extended parameter value.

    Handles the charset and language prefix: "UTF-8''..." where the remainder is percent-encoded.

    decoded_filename

    fn decoded_filename(cd : ContentDisposition) -> String?

    Get a decoded filename from a Content-Disposition, handling RFC 2231.

    detect_charset

    fn detect_charset(params : Array[(String, String)]) -> String

    Detect the character set name from a Content-Type parameter. Returns "us-ascii" as the default.

    disposition_param

    fn disposition_param(cd : ContentDisposition, name : String) -> String?

    Look up a parameter value by name in a ContentDisposition.

    disposition_to_string

    fn disposition_to_string(cd : ContentDisposition) -> String

    Convert a ContentDisposition into a header value string.

    email_address

    fn email_address(local_part~ : String, domain~ : String) -> EmailAddress

    Create a simple text email address.

    email_date

    fn email_date(year~ : Int, month~ : Int, day~ : Int, hour? : Int, minute? : Int, second? : Int, tz_hour? : Int, tz_minute? : Int, tz_sign? : Int) -> EmailDate

    Create an EmailDate value from its components.

    email_date_to_iso

    fn email_date_to_iso(d : EmailDate) -> String

    Format an EmailDate to a compact ISO-like string (for diagnostics).

    email_date_to_string

    fn email_date_to_string(d : EmailDate) -> String

    Format an EmailDate as an RFC 5322 date-time string. Output format: "Mon, 01 Jan 2026 12:34:56 +0800"

    empty_message

    fn empty_message() -> Message

    Create a new empty message.

    encode_encoded_word_b

    fn encode_encoded_word_b(s : String) -> String

    Encode a non-ASCII string using RFC 2047 encoded-word Base64 form. Only encodes if the input contains non-ASCII characters.

    encode_encoded_word_q

    fn encode_encoded_word_q(s : String) -> String

    Encode a non-ASCII string using RFC 2047 encoded-word Q form. Spaces become '_' in the encoded form.

    encode_header_for_output

    fn encode_header_for_output(value : String) -> String

    Encode a header value for output: non-ASCII text becomes an RFC 2047 encoded-word. ASCII-only values pass through unchanged.

    eq_ignore_case

    fn eq_ignore_case(a : String, b : String) -> Bool

    Case-insensitive string comparison.

    fold_header_value

    fn fold_header_value(name : String, value : String) -> String

    Fold a header value at 78 columns using RFC 5322 folding rules. Continuation lines start with a single space.

    format_rfc5322_date

    fn format_rfc5322_date(d : EmailDate) -> String

    Format an EmailDate in RFC 5322 format with full weekday.

    generate_boundary

    fn generate_boundary(seed? : Int) -> String

    Generate a random boundary string from a seed.

    generate_message_id

    fn generate_message_id(domain : String, timestamp? : Int) -> MessageId

    Generate a unique Message-ID for a new message. Format: prefix.timestamp@domain The timestamp is derived from a caller-provided value so the function stays pure and deterministic for testing.

    get_header

    fn get_header(msg : Message, name : String) -> String?

    Look up a header by name (case-insensitive). Returns None if the header is not found.

    get_headers

    fn get_headers(msg : Message, name : String) -> Array[String]

    Look up all headers matching a name (case-insensitive).

    has_encoded_words

    fn has_encoded_words(input : String) -> Bool

    Check whether a header value contains any RFC 2047 encoded-word.

    has_header

    fn has_header(msg : Message, name : String) -> Bool

    Check whether a message has a header with the given name (case-insensitive).
    fn header(name~ : String, value~ : String) -> Header

    Create a new header.

    hex_char_to_int

    fn hex_char_to_int(c : Char) -> Int?

    Convert a hex character to its integer value (0-15).

    html_escape

    fn html_escape(s : String) -> String

    Escape a string for inclusion in HTML content.

    html_to_text

    fn html_to_text(html : String) -> String

    Convert an HTML string to plain text by stripping tags.

    html_unescape

    fn html_unescape(s : String) -> String

    Decode common HTML entities back to characters.

    is_application

    fn is_application(ct : ContentType) -> Bool

    Check whether a ContentType is an application type.

    is_ascii_compatible_charset

    fn is_ascii_compatible_charset(name : String) -> Bool

    Check whether a charset is a single-byte ASCII-compatible encoding.

    is_ascii_only

    fn is_ascii_only(s : String) -> Bool

    Check whether a string contains only ASCII characters (0-127).

    is_attachment

    fn is_attachment(part : MimePart) -> Bool

    Check whether a MIME part is an attachment (has attachment disposition).

    is_bounce

    fn is_bounce(msg : Message) -> Bool

    Check whether the message is a bounce/undeliverable notice.

    is_image

    fn is_image(ct : ContentType) -> Bool

    Check whether a ContentType is an image type.

    is_ipv4

    fn is_ipv4(s : String) -> Bool

    Check whether a string is a valid IPv4 domain literal.

    is_leap_year

    fn is_leap_year(year : Int) -> Bool

    Check whether a year is a leap year.

    is_multipart

    fn is_multipart(ct : ContentType) -> Bool

    Check whether a ContentType is a multipart type.

    is_printable_ascii

    fn is_printable_ascii(s : String) -> Bool

    Check whether a string is valid printable ASCII text.

    is_reply

    fn is_reply(msg : Message) -> Bool

    Check whether the message is a reply (has In-Reply-To or References).

    is_text

    fn is_text(ct : ContentType) -> Bool

    Check whether a ContentType is a text type.

    mailbox

    fn mailbox(display_name? : String, address~ : EmailAddress?) -> Mailbox

    Create a Mailbox value.

    mailbox_addresses

    fn mailbox_addresses(mbs : Array[Mailbox]) -> Array[EmailAddress]

    Get all EmailAddress values from an array of Mailboxes.

    mailbox_display_name

    fn mailbox_display_name(mb : Mailbox) -> String

    Get the display name from a Mailbox, or the local part if empty.

    mailbox_list_to_string

    fn mailbox_list_to_string(mbs : Array[Mailbox]) -> String

    Convert a list of Mailboxes to a comma-separated string.

    mailbox_to_string

    fn mailbox_to_string(mb : Mailbox) -> String

    Format a Mailbox back to a string.

    make_html_message

    fn make_html_message(from~ : String, to~ : String, subject~ : String, text_body~ : String, html_body~ : String) -> Message

    Build an HTML message with a text/plain alternative part.

    make_multipart_message

    fn make_multipart_message(from~ : String, to~ : String, subject~ : String, parts~ : Array[MimePart]) -> Message

    Create a multipart/mixed message from text and attachment parts.

    make_text_message

    fn make_text_message(from~ : String, to~ : String, subject~ : String, body~ : String, cc? : String) -> Message

    Build a plain-text message from common fields.

    merge_extended_params

    fn merge_extended_params(params : Array[(String, String)]) -> Array[(String, String)]

    Merge RFC 2231 parameter continuations into complete parameter values.

    Handles both:
    • Single-part extended values: name*=charset'lang'value
    • Continued values: name0=..., name1=..., name*2=...

    message_all_addresses

    fn message_all_addresses(msg : Message) -> Array[Mailbox]

    Extract all email addresses from the From, To, Cc, and Bcc headers.

    message_boundary

    fn message_boundary(msg : Message) -> String?

    Get the boundary parameter of a multipart message.

    message_cc_mailboxes

    fn message_cc_mailboxes(msg : Message) -> Array[Mailbox]

    Get the parsed Cc addresses of a message as Mailboxes.

    message_content_type

    fn message_content_type(msg : Message) -> ContentType?

    Get the Content-Type of a message as a parsed ContentType.

    message_date

    fn message_date(msg : Message) -> EmailDate?

    Get the parsed Date from a Message, if present and valid.

    message_decoded_content_type

    fn message_decoded_content_type(msg : Message) -> ContentType?

    Get the Content-Type of a message as a decoded ContentType. RFC 2231 extended parameters are merged.

    message_decoded_disposition

    fn message_decoded_disposition(msg : Message) -> ContentDisposition?

    Get the Content-Disposition of a message as a decoded ContentDisposition.

    message_from_mailboxes

    fn message_from_mailboxes(msg : Message) -> Array[Mailbox]

    Get the parsed From addresses of a message as Mailboxes.

    message_header_count

    fn message_header_count(msg : Message) -> Int

    Get the number of headers in a message.

    message_id

    fn message_id(id~ : String, domain~ : String) -> MessageId

    Create a MessageId value.

    message_id_to_string

    fn message_id_to_string(mid : MessageId) -> String

    Format a MessageId as an RFC 5322 Message-ID header value.

    message_in_reply_to

    fn message_in_reply_to(msg : Message) -> Array[MessageId]

    Get the In-Reply-To header of a message as a list of MessageIds.

    message_list_unsubscribe

    fn message_list_unsubscribe(msg : Message) -> String?

    Get the List-Unsubscribe header, if present.

    message_message_id

    fn message_message_id(msg : Message) -> MessageId?

    Get the Message-ID of a message, if present.

    message_priority

    fn message_priority(msg : Message) -> String?

    Check whether a message has a priority header.

    message_received_chain

    fn message_received_chain(msg : Message) -> Array[ReceivedInfo]

    Get the Received chain of a message (topmost first).

    message_references

    fn message_references(msg : Message) -> Array[MessageId]

    Get the References header of a message as a list of MessageIds.

    message_reply_to

    fn message_reply_to(msg : Message) -> Array[Mailbox]

    Get the Reply-To addresses of a message, falling back to From.

    message_return_path

    fn message_return_path(msg : Message) -> EmailAddress?

    Get the Return-Path address, if present.

    message_sender

    fn message_sender(msg : Message) -> Array[Mailbox]

    Get the sender address (Sender header or From).

    message_subject

    fn message_subject(msg : Message) -> String

    Get the decoded Subject of a message. RFC 2047 encoded-words are decoded to plain text.

    message_to_mailboxes

    fn message_to_mailboxes(msg : Message) -> Array[Mailbox]

    Get the parsed To addresses of a message as Mailboxes.

    message_to_string

    fn message_to_string(msg : Message) -> String

    Serialize a Message to RFC 5322 format text.

    multipart_part

    fn multipart_part(sub_type~ : String, boundary~ : String, parts~ : Array[MimePart]) -> MimePart

    Create a new multipart MIME part.

    parse

    fn parse(input : String) -> Message

    Parse a raw email string into a Message AST.

    parse_address

    fn parse_address(input : String) -> EmailAddress?

    Parse a single email address from a string. Supports: user@domain, user@domain, "Name" user@domain

    parse_address_list

    fn parse_address_list(input : String) -> Array[EmailAddress]

    Parse multiple email addresses from a header value.

    parse_content_disposition

    fn parse_content_disposition(value : String) -> ContentDisposition?

    Parse a MIME Content-Disposition header value.

    parse_content_type

    fn parse_content_type(value : String) -> ContentType?

    Parse a MIME Content-Type header value.

    parse_date_header

    fn parse_date_header(value : String) -> EmailDate?

    Parse a Date header value from a Message and return the EmailDate.

    parse_email_date

    fn parse_email_date(input : String) -> EmailDate?

    Parse an RFC 5322 date-time string into an EmailDate.

    Accepts formats such as: "Mon, 01 Jan 2026 12:34:56 +0800" "1 Jan 2026 12:34:56 GMT" "Tue, 2 Feb 2026 08:00:00 -0500 (EST)"

    Returns None if the value cannot be parsed.

    parse_mailbox

    fn parse_mailbox(input : String) -> Mailbox?

    Parse a full mailbox into a Mailbox value.

    Handles formats: user@example.com user@example.com Display Name user@example.com "Display Name" user@example.com Display Name (comment) user@example.com

    parse_mailbox_list

    fn parse_mailbox_list(input : String) -> Array[Mailbox]

    Parse an address list that may contain groups.

    Returns all mailbox addresses found. Group members are flattened into the result list.

    parse_message

    fn parse_message(input : String) -> Message

    Parse a full email message from raw text. Splits headers from body at the first blank line.

    parse_message_id

    fn parse_message_id(input : String) -> MessageId?

    Parse a Message-ID header value into a MessageId. Accepts "id@domain" with optional surrounding whitespace.

    parse_message_ids

    fn parse_message_ids(input : String) -> Array[MessageId]

    Parse a Message-ID or a space-separated list of Message-IDs. Handles both "a@b" and "a@b c@d" formats.

    parse_mime

    fn parse_mime(input : String) -> Message

    Parse a MIME message with full multipart support.

    parse_mime_message

    fn parse_mime_message(input : String) -> Message

    Parse a full MIME message from raw text. Returns a Message with an optional MimePart tree.

    parse_received_header

    fn parse_received_header(value : String) -> ReceivedInfo

    Parse a Received header value into structured ReceivedInfo.

    Format: from a by b with c for d; date Each clause is optional; date follows the ';'.

    part_body_text

    fn part_body_text(part : MimePart) -> String?

    Extract the text content of a MIME part as a string. For text parts returns the decoded text; for binary parts returns None.

    part_filename

    fn part_filename(part : MimePart) -> String?

    Get the filename from a MIME part, if any.

    percent_decode

    fn percent_decode(input : String) -> String?

    Percent-decode a string: %XX sequences become their byte values. Multi-byte UTF-8 sequences are decoded into Unicode characters.

    plain_text

    fn plain_text(part : MimePart) -> String?

    Get the plain-text content from a MIME part tree, if any.

    qp_decode

    fn qp_decode(input : String) -> String?

    Decode a Quoted-Printable encoded string (RFC 2045 6.7). Handles soft line breaks (=CRLF, =LF) and hex escapes (=XX).

    qp_encode_bytes

    fn qp_encode_bytes(data : Array[Int]) -> String

    Encode a byte sequence as Quoted-Printable (RFC 2045 6.7). Non-printable bytes and '=' are escaped as =XX. Soft line breaks are inserted at 75 columns.

    qp_encode_text

    fn qp_encode_text(s : String) -> String

    Encode a text string as Quoted-Printable.

    quote_header_string

    fn quote_header_string(s : String) -> String

    Quote a string for use in a quoted-string header value.

    received_info

    fn received_info(from_? : String, by? : String, with_? : String, for_? : String, date? : String) -> ReceivedInfo

    Create a ReceivedInfo value.

    render_folded_message

    fn render_folded_message(msg : Message) -> String

    Render a message with folded headers.

    render_mime_tree

    fn render_mime_tree(part : MimePart) -> String

    Render a MIME part tree with proper boundaries and content encodings.

    render_text_message

    fn render_text_message(msg : Message) -> String

    Render a plain-text message (without MIME) to a string.

    same_message

    fn same_message(a : Message, b : Message) -> Bool

    Check whether two messages have the same Message-ID.

    sanitize_text

    fn sanitize_text(s : String) -> String

    Convert a body to a safe plain-text form for display.

    serialize_encoded_headers

    fn serialize_encoded_headers(headers : Array[Header]) -> String

    Serialize headers with RFC 2047 encoding applied to values.

    serialize_header_block

    fn serialize_header_block(headers : Array[Header]) -> String

    Serialize a header block (all headers + blank line).

    serialize_mailboxes

    fn serialize_mailboxes(mbs : Array[Mailbox]) -> String

    Serialize a list of mailboxes into a header value string.

    simple_hash

    fn simple_hash(s : String) -> Int

    Compute a simple non-cryptographic hash of a string (for indexing).

    starts_with_ignore_case

    fn starts_with_ignore_case(s : String, prefix : String) -> Bool

    Case-insensitive prefix check.

    strip_comments

    fn strip_comments(input : String) -> String

    Strip comments (parenthesized text) from a header value.

    summarize_message

    fn summarize_message(msg : Message) -> String

    Summarize a message: Subject, From, and Date in one string.

    text_part

    fn text_part(body~ : String) -> MimePart

    Create a new text-only MIME part.

    to_string

    fn to_string(msg : Message) -> String

    Serialize a Message back to RFC 5322 format text.

    to_timestamp

    fn to_timestamp(d : EmailDate) -> Int

    Convert an EmailDate to a Unix-like timestamp (seconds since epoch). Uses a simplified days-from-civil algorithm.

    tokenize

    fn tokenize(input : String) -> Array[Token]

    Tokenize the entire input into a sequence of tokens. This is the main entry point for the lexer.

    truncate

    fn truncate(s : String, max_len : Int) -> String

    Truncate a string to a maximum length, appending "..." if truncated.

    tz_offset_minutes

    fn tz_offset_minutes(d : EmailDate) -> Int

    Get the numeric timezone offset of an EmailDate in minutes.

    url_encode

    fn url_encode(s : String) -> String

    URL-encode a string (percent-encoding) for RFC 2231 parameters. Spaces become %20; unreserved characters pass through.

    utf8_decode

    fn utf8_decode(bytes : Array[Int]) -> String

    Decode UTF-8 bytes into a string. Returns the decoded string; invalid sequences become replacement chars.

    utf8_encode

    fn utf8_encode(s : String) -> Array[Int]

    Encode a string as UTF-8 bytes, returning an array of bytes. Non-ASCII characters are encoded as 2-4 byte sequences.

    valid_header_name

    fn valid_header_name(name : String) -> Bool

    Check whether a string is a valid email header name.

    validate_date

    fn validate_date(d : EmailDate) -> Bool

    Validate a parsed EmailDate: checks ranges and month/day consistency.

    validate_domain

    fn validate_domain(domain : String) -> Bool

    Validate a domain per RFC 5322: letters, digits, hyphen, and dots.

    validate_email_address

    fn validate_email_address(addr : EmailAddress) -> Bool

    Validate a full email address (local part and domain).

    validate_local_part

    fn validate_local_part(local_part : String) -> Bool

    Validate a local part per RFC 5322. Accepts dot-atom and quoted-string forms.