'\" t
.\"<!-- Copyright 2001-2025 S. Varshavchik.  See COPYING for -->
.\"<!-- distribution information. -->
.\"     Title: rfc822
.\"    Author: Sam Varshavchik
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\"      Date: 06/18/2026
.\"    Manual: S. Varshavchik.
.\"    Source: Courier Mail Server
.\"  Language: English
.\"
.TH "RFC822" "3" "06/18/2026" "Courier Mail Server" "S\&. Varshavchik\&."
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
rfc822 \- RFC 822 parsing library
.SH "SYNOPSIS"
.sp
.nf
#include <rfc822\&.h>

#include <rfc2047\&.h>

g++ \&.\&.\&. \-lrfc822
.fi
.SH "DESCRIPTION"
.PP
The rfc822 library provides C++ classes for parsing E\-mail headers in the RFC 822 format\&. This library also includes some functions to help with encoding and decoding 8\-bit text, as defined by RFC 2047\&.
.PP
The format used by E\-mail headers to encode sender and recipient information is defined by
\m[blue]\fBRFC 822\fR\m[]\&\s-2\u[1]\d\s+2
(and its successor,
\m[blue]\fBRFC 2822\fR\m[]\&\s-2\u[2]\d\s+2)\&. The format allows the actual E\-mail address and the sender/recipient name to be expressed together, for example:
John Smith <jsmith@example\&.com>
.PP
The main purposes of the rfc822 library is to:
.sp
.RS 4
.ie n \{\
\h'-04' 1.\h'+01'\c
.\}
.el \{\
.sp -1
.IP "  1." 4.2
.\}
Parse a text string containing a list of RFC 822\-formatted addresses into its logical components: names and E\-mail addresses\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04' 2.\h'+01'\c
.\}
.el \{\
.sp -1
.IP "  2." 4.2
.\}
Access those individual components\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04' 3.\h'+01'\c
.\}
.el \{\
.sp -1
.IP "  3." 4.2
.\}
Allow some limited modifications of the parsed structure, and then convert it back into a text string\&.
.RE
.SS "Tokenizing an E\-mail header"
.sp
.if n \{\
.RS 4
.\}
.nf
std::string_view header;

rfc822::tokens tokens{header};

for (rfc822::token &t:token)
    ;
.fi
.if n \{\
.RE
.\}
.PP
rfc822::tokens
is a container of tokenized parts of E\-mail addresses\&. It is constructed from a
std::string_view
that contains E\-mail addresses\&.
.if n \{\
.sp
.\}
.RS 4
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBNote\fR
.ps -1
.br
.PP
The underlying text string must not be destroyed as long as the
rfc822::tokens
object is in scope\&.
.sp .5v
.RE
.TS
tab(:);
lB s s s.
T{
struct rfc822::token {
T}
.T&
l l l l
l l l l
lB s s s.
T{
\ \&
T}:T{
\fBint\fR
T}:T{
type;
T}:T{
.if n \{\
.RS 4
.\}
.nf
// RFC 822 atom
.fi
.if n \{\
.RE
.\}
T}
T{
\ \&
T}:T{
std::string_view
T}:T{
str;
T}:T{
.if n \{\
.RS 4
.\}
.nf
// underlying text
.fi
.if n \{\
.RE
.\}
T}
T{
};
T}
.TE
.sp 1
.PP
The
\fItype\fR
field contains one of the RFC 822 atoms, such as
\(lq@\(rq
or
\(lq;\(rq\&. The
\fIstr\fR
field contains atom\*(Aqs text\&. It references a substring of the original string that was passed to
rfc822::tokens
constructor\&.
\fIstr\fR
references a substring for
\*(Aq\e0\*(Aq,
\*(Aq"\*(Aq,
\*(Aq(\*(Aq
atoms\&. In all other cases,
\fIstr\fR
is an empty string\&. Possible values of
\fItype\fR:
.PP
\*(Aq\e0\*(Aq
.RS 4
This is a simple atom \- a sequence of non\-special characters that is delimited by whitespace or special characters (see below)\&.
.RE
.PP
\*(Aq"\*(Aq
.RS 4
This is a quoted string\&.
.RE
.PP
\*(Aq(\*(Aq
.RS 4
This is an old style comment\&. A deprecated form of E\-mail addressing uses \- for example \- "john@example\&.com (John Smith)" instead of "John Smith <john@example\&.com>"\&. This old\-style notation defined parenthesized content as arbitrary comments\&. The
rfc822::token
with
\fItype\fR
set to \*(Aq(\*(Aq is created for the entire comment, including the parentheses\&.
.RE
.PP
Symbols: \*(Aq<\*(Aq, \*(Aq>\*(Aq, \*(Aq@\*(Aq, and many others
.RS 4
The remaining possible values of
\fItype\fR
include all the characters in RFC 822 headers that have special significance\&.
.RE
.SS "Extracting E\-mail addresses"
.sp
.if n \{\
.RS 4
.\}
.nf
rfc822::addresses addresses{tokens};

for (rfc822::address &a:addresses)
    ;
.fi
.if n \{\
.RE
.\}
.PP
rfc822::addresses
is a container of E\-mail addresses that were parsed from a
rfc822::tokens
object\&.
.TS
tab(:);
lB s s s.
T{
struct rfc822::address {
T}
.T&
l l l l
l l l l
lB s s s.
T{
\ \&
T}:T{
rfc822::tokens
T}:T{
name;
T}:T{
.if n \{\
.RS 4
.\}
.nf
// Name portion of an address
.fi
.if n \{\
.RE
.\}
T}
T{
\ \&
T}:T{
rfc822::tokens
T}:T{
address;
T}:T{
.if n \{\
.RS 4
.\}
.nf
// E\-mail address
.fi
.if n \{\
.RE
.\}
T}
T{
};
T}
.TE
.sp 1
.PP
The
rfc822::address
class has two fields:
\fIname\fR
and
\fIaddress\fR\&.
\fIname\fR
contains the name portion of an address, which is a sequence of tokens\&.
\fIaddress\fR
contains the E\-mail address itself, which is also a sequence of tokens\&.
.PP
For example, the following is a valid E\-mail header:
.sp
.if n \{\
.RS 4
.\}
.nf
To: recipient\-list: tom@example\&.com, john@example\&.com;
.fi
.if n \{\
.RE
.\}
.PP
Typically, all of this, except for "To:", gets parsed by creating a
rfc822::tokens
object, then a
rfc822::addresses
object\&. The
"recipient\-list:"
and the trailing semicolon is a legacy mailing list specification that is no longer in widespread use, but must still must be accounted for\&.
.PP
The resulting
rfc822::addresses
object will have four
rfc822::address
structures: one for "recipient\-list:"; one for each address; and one for the trailing semicolon\&.
.PP
If
\fIaddress\fR
in a
rfc822::address
is an empty container, then this structure represents some non\-address portion of the original header, such as "recipient\-list:" or a semicolon\&. Otherwise it contains a tokenized representation of the E\-mail address\&.
.PP
\fIname\fR
either contains the tokenized form of a non\-address portion of the original header, or a tokenized form of the recipient\*(Aqs name\&.
\fIname\fR
will be an empty container if the recipient name was not provided\&.
.PP
For example, for the following address:
Tom Jones <tjones@example\&.com>
\- the
\fIaddress\fR
field contains the tokenized form of "tjones@example\&.com", and
\fIname\fR
contains the tokenized form of "Tom Jones"\&.
.SS "Working with 8\-bit MIME\-encoded headers"
.sp
.if n \{\
.RS 4
.\}
.nf
const auto &[string, error] = rfc2047::encode(U"header", "utf\-8",
    rfc2047::qp_allow_any);

.fi
.if n \{\
.RE
.\}
.PP
The
\fBrfc2047::encode\fR() function template and the
\fBrfc2047::decode\fR() function object provide additional logic to encode or decode 8\-bit content in 7\-bit RFC 822 headers, as specified in RFC 2047\&.
.PP
\fBrfc2047::encode\fR()\*(Aqs first parameter is a
std::string
in the character set specified by the second parameter\&. The third parameter is a function that returns true if the character should be encoded\&. The following functions are predefined:
.PP
rfc2047::qp_allow_any
.RS 4
All characters are allowed to be unencoded, except a small number of characters that have special meaning in RFC 2047: control characters, eight\-bit characters, and several characters that would break the tokenization of the header\&.
.RE
.PP
rfc2047::qp_allow_comments
.RS 4
Also parenthesis and quotes are allowed to be unencoded\&.
.RE
.PP
rfc2047::qp_allow_word
.RS 4
Allow only characters used in base64 encoded MIME entities, and a few other characters\&.
.RE
.PP
Instead of a single string of text, an overloaded
\fBrfc2047::encode\fR() function template accepts a beginning and an ending iterator for a sequence of characters to be encoded\&.
.PP
\fBrfc2047::decode\fR() parses a string in RFC 2047 format\&. It is a somewhat complicated template that implements a callback\-based parser\&. Consult the inline comments for a more detailed explanation of how to use it\&.
\fBrfc2047::decode_unicode\fR() does the same but it decodes to a Unicode string, and ignores the character set and language of the encoded word (the character set effects the conversion to a Unicode character stream, and the language is immaterial)\&.
.sp
.if n \{\
.RS 4
.\}
.nf
std::u32string ustr;

rfc822::tokens name, address;

address\&.unicode_address(std::back_inserter(ustr));
name\&.unicode_name(std::back_inserter(ustr), false);

std::string str;

address\&.display_address(unicode_default_chset(),
			std::back_inserter(str));
name\&.display_name(unicode_default_chset(),
		  std::back_inserter(str), false);

display_header_unicode("To:", "nobody@example\&.com",
    std::back_inserter(ustr),
    []
    {
    }
);

display_header("To", "nobody@example\&.com",
    unicode_default_chset(),
    std::back_inserter(str),
    []
    {
    }
);

std::vector<std::u32string> ulines;

rfc2047::wrap_header_unicode("Subject", "Hello world", 80,
    std::back_inserter(ulines)
);

std::vector<std::string> lines;

rfc2047::wrap_header("Subject:", "Hello world", 80,
    unicode_default_chset(),
    std::back_inserter(lines)
);

rfc822::address &address;

address\&.encode(unicode_default_chset(), std::back_inserter(str));

.fi
.if n \{\
.RE
.\}
.PP
The
\(lqrfc2047\(rq
namespace contains several functions that handle various kinds of encoding and decoding between 8\-bit content in 7\-bit RFC 822 headers\&. These functions implement the specification in RFC 2047, and related standards\&. These functions write their output to an output iterator that gets passed as one of the parameters\&. If an output iterator gets passed by value, the function returns the value of the output iterator after it has been advanced for each character written to it\&. If the output iterator is passed by reference, the function returns void, and the output iterator itself is modified\&.
.PP
The following functions are available:
.PP
\fBrfc822::tokens::unicode_address\fR, \fBrfc822::tokens::unicode_name\fR
.RS 4
A method of the
rfc822::tokens
class, used to convert the parsed contents of an RFC 822 address or name into a sequence of Unicode characters\&.
\fBunicode_name\fR() uses RFC 2047 to decode any RFC 2047\-encoded words\&.
\fBunicode_address\fR() uses IDN encoding to convert any IDN\-encoded domain names into Unicode\&.
.RE
.PP
\fBrfc822::tokens::display_address\fR, \fBrfc822::tokens::display_name\fR
.RS 4
Convert a sequence of
rfc822::tokenss containing either an IDN\-encoded address or an RFC\-2047 encoded name into a sequence of characters in the specified character set\&.
.sp
\fBdisplay_name\fR()\*(Aqs third parameter is a flag\&. A
true
value strips off quotes or parentheses from the display name\&.
.RE
.PP
\fBdisplay_header_unicode\fR
.RS 4
This function takes the name of a header and its contents, and converts the contents into a sequence of Unicode characters\&. The passed in header name determines how the header gets parsed\&. Headers containing addresses are handled by parsing them as addresses, then converting the result into a sequence of Unicode characters using
\fBunicode_name\fR() and
\fBunicode_address\fR()\&. Other headers are parsed as unstructured headers, using RFC 2047 to decode any RFC 2047\-encoded words\&.
.sp
The fourth parameter is an optional callback that gets invoked at every line\-breaking opportunity\&. The callback gets invoked after writing, to the output iterator, the sequence of characters that end in a line\-breaking opportunity, and before writing the first character after the potential line\-break\&.
.RE
.PP
\fBrfc2047::display_header\fR
.RS 4
Take an arbitrary header, and convert it into a sequence of characters in the specified character set\&. This is, basically, the same as
\fBdisplay_header_unicode\fR() but the returned string is in the specified character set\&.
.RE
.PP
\fBrfc2047::wrap_header_unicode\fR
.RS 4
This uses
\fBdisplay_header_unicode\fR, but then it wraps the resulting sequence of characters into a sequence of lines, using the passed in maximum line width\&. The passed in output iterator iterates over a sequnce of unicode strings\&.
.RE
.PP
\fBrfc2047::wrap_header\fR
.RS 4
This uses
\fBwrap_header_unicode\fR, but then it converts the resulting sequence of Unicode characters into a sequence of 8\-bit strings, using the passed in character set\&. The passed in output iterator iterates over a sequence of 8\-bit strings\&.
.RE
.PP
\fBrfc2047::encode\fR
.RS 4
Encode a sequence of 8\-bit strings into a sequence of RFC 2047\-encoded words\&. The passed in output iterator iterates over a sequence of RFC 2047\-encoded words\&.
.RE
.PP
\fBrfc822::address::encode\fR
.RS 4
This method takes the name and address portion of a
rfc822::address, that was encoded in the given character set, and encodes them using RFC 2047 and IDN, as appropriate\&. The output is written to the passed in output iterator\&.
.RE
.SS "Working with subjects"
.sp
.if n \{\
.RS 4
.\}
.nf
const auto &[str, flags]=rfc822::coresubj("Re: your message");

const auto &[str, flags]=rfc822::coresubj_nouc("Re: your message");

const auto &[str, flags]=rfc822::coresubj_keepblobs("Re: your message");

.fi
.if n \{\
.RE
.\}
.PP
These functions take the contents of the subject header, and return the "core" subject header that\*(Aqs used in the specification of the IMAP THREAD function\&. These functions are designed to strip all subject line artifacts that might\*(Aqve been added in the process of forwarding or replying to a message\&. These functions return a tuple of a string and an
\fBint\fR
flag value\&. Currently,
\fBrfc822::coresubj\fR() performs the following transformations:
.PP
Whitespace
.RS 4
Leading and trailing whitespace is removed\&. Consecutive whitespace characters are collapsed into a single whitespace character\&.
.RE
.PP
Re:, (fwd) [foo]
.RS 4
These artifacts (and several others) are removed from the subject line\&.
.RE
.PP
\fBrfc822::coresubj\fR
.RS 4
This is the original version of this function\&. It is preserved for binary compatibility with existing programs\&.
.RE
.PP
\fBrfc822::coresubj_nouc\fR
.RS 4
The returned string does not get converted to uppercase\&.
.RE
.PP
\fBrfc822::coresubj_keepblobs\fR
.RS 4
This is like
\fBrfc822::coresubj_nouc\fR(), except that it does not remove [blob] markers from the returned subject line\&.
.RE
.PP
Note that these functions do NOT do MIME decoding\&. In order to implement IMAP THREAD, it is necessary to call something like
\fBrfc2047_decode\fR() before calling
\fBrfc822::coresubj\fR()\&.
.PP
The returned flag value is a bitmask:
.PP
CORESUBJ_RE
.RS 4
This indicates that the original subject line starts with
Re:\&.
.RE
.PP
CORESUBJ_FWD
.RS 4
This indicates that the original subject line contained a
(fwd)
marker\&.
.RE
.SH "SEE ALSO"
.PP
\m[blue]\fB\fBrfc2045\fR(3)\fR\m[]\&\s-2\u[3]\d\s+2,
\m[blue]\fB\fBreformail\fR(1)\fR\m[]\&\s-2\u[4]\d\s+2,
\m[blue]\fB\fBreformime\fR(1)\fR\m[]\&\s-2\u[5]\d\s+2\&.
.SH "AUTHOR"
.PP
\fBSam Varshavchik\fR
.RS 4
Author
.RE
.SH "NOTES"
.IP " 1." 4
RFC 822
.RS 4
\%https://datatracker.ietf.org/doc/html/rfc822
.RE
.IP " 2." 4
RFC 2822
.RS 4
\%https://datatracker.ietf.org/doc/html/rfc2822
.RE
.IP " 3." 4
\fBrfc2045\fR(3)
.RS 4
\%http://www.courier-mta.org/rfc2045.html
.RE
.IP " 4." 4
\fBreformail\fR(1)
.RS 4
\%http://www.courier-mta.org/reformail.html
.RE
.IP " 5." 4
\fBreformime\fR(1)
.RS 4
\%http://www.courier-mta.org/reformime.html
.RE
