(*--------------------------------------------------------------------------- Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) (** Email header types as defined in RFC 8621 Section 4.1.2 @canonical Jmap.Proto.Email_header *) (** {1 Raw Headers} *) (** A raw email header name-value pair. *) type t = { name : string; (** The header field name. *) value : string; (** The raw header field value. *) } val create : name:string -> value:string -> t val name : t -> string val value : t -> string val jsont : t Jsont.t (** {1 Header Categories} RFC 8621 Section 4.1.2 restricts which parsed forms can be used with which headers. These polymorphic variant types encode those restrictions at the type level. Each category corresponds to headers that share the same allowed forms: - Address headers: can use [Addresses] and [Grouped_addresses] forms - Message-ID headers: can use [Message_ids] form - Date headers: can use [Date] form - URL headers: can use [Urls] form - Text headers: can use [Text] form - All headers can use [Raw] form - Custom headers (not in RFC 5322/2369) can use any form *) (** Headers that allow the [Addresses] and [Grouped_addresses] forms. These are address-list headers per RFC 5322. *) type address_header = [ | `From | `Sender | `Reply_to | `To | `Cc | `Bcc | `Resent_from | `Resent_sender | `Resent_reply_to | `Resent_to | `Resent_cc | `Resent_bcc ] (** Headers that allow the [Message_ids] form. These contain msg-id values per RFC 5322. *) type message_id_header = [ | `Message_id | `In_reply_to | `References | `Resent_message_id ] (** Headers that allow the [Date] form. These contain date-time values per RFC 5322. *) type date_header = [ | `Date | `Resent_date ] (** Headers that allow the [Urls] form. These are list-* headers per RFC 2369. *) type url_header = [ | `List_help | `List_unsubscribe | `List_subscribe | `List_post | `List_owner | `List_archive ] (** Headers that allow the [Text] form. These contain unstructured or phrase content. *) type text_header = [ | `Subject | `Comments | `Keywords | `List_id ] (** All standard headers defined in RFC 5322 and RFC 2369. *) type standard_header = [ | address_header | message_id_header | date_header | url_header | text_header ] (** A custom header not defined in RFC 5322 or RFC 2369. Custom headers can use any parsed form. *) type custom_header = [ `Custom of string ] (** Any header - standard or custom. *) type any_header = [ standard_header | custom_header ] (** {2 Header Name Conversion} *) val standard_header_to_string : [< standard_header ] -> string (** Convert a standard header variant to its wire name (e.g., [`From] -> "From"). *) val standard_header_of_string : string -> standard_header option (** Parse a header name to a standard header variant, case-insensitive. Returns [None] for non-standard headers. *) val any_header_to_string : [< any_header ] -> string (** Convert any header variant to its wire name. *) (** {1 Header Parsed Forms} RFC 8621 defines several parsed forms for headers. These can be requested via the [header:Name:form] properties. *) (** The parsed form to request for a header value. *) type form = [ | `Raw (** Raw octets, available for all headers *) | `Text (** Decoded text, for text headers or custom *) | `Addresses (** Flat address list, for address headers or custom *) | `Grouped_addresses (** Address list with groups, for address headers or custom *) | `Message_ids (** List of message-id strings, for message-id headers or custom *) | `Date (** Parsed date, for date headers or custom *) | `Urls (** List of URLs, for url headers or custom *) ] val form_to_string : [< form ] -> string (** Convert form to wire suffix (e.g., [`Addresses] -> "asAddresses"). [`Raw] returns the empty string (raw is the default). *) val form_of_string : string -> form option (** Parse a form suffix (e.g., "asAddresses" -> [`Addresses]). Empty string returns [`Raw]. *) (** {1 Header Property Requests} Type-safe construction of [header:Name:form:all] property strings. The GADT ensures that only valid form/header combinations are allowed. *) (** A header property request with type-safe form selection. The type parameter encodes what forms are allowed: - Address headers allow [Addresses] and [Grouped_addresses] - Message-ID headers allow [Message_ids] - Date headers allow [Date] - URL headers allow [Urls] - Text headers allow [Text] - All headers allow [Raw] - Custom headers allow any form *) type header_property = | Raw of { name : string; all : bool } (** Raw form, available for any header. *) | Text of { header : [ text_header | custom_header ]; all : bool } (** Text form, for text headers or custom. *) | Addresses of { header : [ address_header | custom_header ]; all : bool } (** Addresses form, for address headers or custom. *) | Grouped_addresses of { header : [ address_header | custom_header ]; all : bool } (** GroupedAddresses form, for address headers or custom. *) | Message_ids of { header : [ message_id_header | custom_header ]; all : bool } (** MessageIds form, for message-id headers or custom. *) | Date of { header : [ date_header | custom_header ]; all : bool } (** Date form, for date headers or custom. *) | Urls of { header : [ url_header | custom_header ]; all : bool } (** URLs form, for URL headers or custom. *) val header_property_to_string : header_property -> string (** Convert a header property request to wire format. E.g., [Addresses { header = `From; all = true }] -> "header:From:asAddresses:all" *) val header_property_of_string : string -> header_property option (** Parse a header property string. Returns [None] if the string doesn't match [header:*] format. *) (** {2 Convenience Constructors} *) val raw : ?all:bool -> string -> header_property (** [raw ?all name] creates a raw header property request. *) val text : ?all:bool -> [ text_header | custom_header ] -> header_property (** [text ?all header] creates a text header property request. *) val addresses : ?all:bool -> [ address_header | custom_header ] -> header_property (** [addresses ?all header] creates an addresses header property request. *) val grouped_addresses : ?all:bool -> [ address_header | custom_header ] -> header_property (** [grouped_addresses ?all header] creates a grouped addresses header property request. *) val message_ids : ?all:bool -> [ message_id_header | custom_header ] -> header_property (** [message_ids ?all header] creates a message-ids header property request. *) val date : ?all:bool -> [ date_header | custom_header ] -> header_property (** [date ?all header] creates a date header property request. *) val urls : ?all:bool -> [ url_header | custom_header ] -> header_property (** [urls ?all header] creates a URLs header property request. *) (** {1 Header Values in Responses} When fetching dynamic headers, the response value type depends on the requested form. This type captures all possible response shapes. *) (** A header value from the response. The variant encodes both the form and whether [:all] was requested: - [*_single] variants: value of the last header instance, or [None] if absent - [*_all] variants: list of values for all instances, empty if absent *) type header_value = | String_single of string option (** Raw or Text form, single instance. *) | String_all of string list (** Raw or Text form, all instances. *) | Addresses_single of Mail_address.t list option (** Addresses form, single instance. *) | Addresses_all of Mail_address.t list list (** Addresses form, all instances. *) | Grouped_single of Mail_address.Group.t list option (** GroupedAddresses form, single instance. *) | Grouped_all of Mail_address.Group.t list list (** GroupedAddresses form, all instances. *) | Date_single of Ptime.t option (** Date form, single instance. *) | Date_all of Ptime.t option list (** Date form, all instances. *) | Strings_single of string list option (** MessageIds or URLs form, single instance. *) | Strings_all of string list option list (** MessageIds or URLs form, all instances. *) val header_value_jsont : form:form -> all:bool -> header_value Jsont.t (** [header_value_jsont ~form ~all] returns a JSON codec for header values with the given form and multiplicity. *) (** {1 Low-level JSON Codecs} These codecs are used internally and for custom header processing. *) (** The raw form - header value as-is. *) val raw_jsont : string Jsont.t (** The text form - decoded and unfolded value. *) val text_jsont : string Jsont.t (** The addresses form - list of email addresses. *) val addresses_jsont : Mail_address.t list Jsont.t (** The grouped addresses form - addresses with group info. *) val grouped_addresses_jsont : Mail_address.Group.t list Jsont.t (** The message IDs form - list of message-id strings. *) val message_ids_jsont : string list Jsont.t (** The date form - parsed RFC 3339 date. *) val date_jsont : Ptime.t Jsont.t (** The URLs form - list of URL strings. *) val urls_jsont : string list Jsont.t