-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A full-featured library for parsing, validating, and rendering email addresses -- -- A modern library for working with email addresses. This package can be -- used to validate user input or handle various flavors of addresses -- that appear in places such as mail messages. -- -- Email addresses can be decoded, manipulated, then rendered back to -- text using the simple local-part@domain format or the more -- complete syntax that allows for display names and comments. -- -- Comprehensive documentation can be found in the Addy module. @package addy @version 0.1.0.0 -- | Internal functions representing character classes in email addresses. -- -- Obsolete characters are only supported in Lenient mode and are -- filtered out after parsing. module Addy.Internal.Char -- | Is a character in the UTF8-non-ascii class from RFC 6532? utf8NonAscii :: Char -> Bool -- | Obsolete control characters. -- --
-- obs-NO-WS-CTL = %d1-8 / ; US-ASCII control -- %d11 / ; characters that do not -- %d12 / ; include the carriage -- %d14-31 / ; return, line feed, and -- %d127 ; white space characters --obsNoWsCtl :: Char -> Bool -- | Whitepace. wsp :: Char -> Bool -- | RFC 5234: Visible character. -- --
-- VCHAR = %x21-7E -- ; visible (printing) characters ---- -- RFC 6532 §3.2 -- --
-- VCHAR =/ UTF8-non-ascii --vchar :: Char -> Bool -- | RFC 5322 §3.2.3 -- --
-- atext = ALPHA / DIGIT / ; Printable US-ASCII
-- "!" / "#" / ; characters not including
-- "$" / "%" / ; specials. Used for atoms.
-- "&" / "'" /
-- "*" / "+" /
-- "-" / "/" /
-- "=" / "?" /
-- "^" / "_" /
-- "`" / "{" /
-- "|" / "}" /
-- "~"
--
--
-- RFC 6532 §3.2
--
-- -- atext =/ UTF8-non-ascii --atext :: Char -> Bool -- | RFC 5322 dtext. -- --
-- dtext = %d33-90 / ; Printable US-ASCII -- %d94-126 / ; characters not including -- obs-dtext ; "[", "]", or "\" -- obs-dtext = obs-NO-WS-CTL / quoted-pair ---- -- RFC 6532 §3.2 -- --
-- dtext =/ UTF8-non-ascii --dtext :: Char -> Bool -- | RFC 5322 ctext. -- --
-- ctext = %d33-39 / ; Printable US-ASCII
-- %d42-91 / ; characters not including
-- %d93-126 / ; "(", ")", or "\"
-- obs-ctext
--
-- obs-ctext = obs-NO-WS-CTL
--
--
-- RFC 6532 §3.2
--
-- -- ctext =/ UTF8-non-ascii --ctext :: Char -> Bool -- | Obsolete ctext. -- --
-- obs-ctext = obs-NO-WS-CTL --ctextObs :: Char -> Bool -- | Characters that can appear in a quoted string. -- -- RFC 5322 §3.2.4: -- --
-- qtext = %d33 / ; Printable US-ASCII -- %d35-91 / ; characters not including -- %d93-126 / ; "\" or the quote character -- obs-qtext ---- -- RFC 6532 §3.2: -- --
-- qtext =/ UTF8-non-ascii --qtext :: Char -> Bool -- | Obsolete qtext. -- --
-- obs-qtext = obs-NO-WS-CTL --qtextObs :: Char -> Bool -- | Characters that can follow a backslash. -- --
-- quoted-pair = ("\" (VCHAR / WSP)) / obs-qp
--
quotedPair :: Char -> Bool
-- | Obsolete characters that can be escaped with a backslash.
--
-- -- obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR) --quotedPairObs :: Char -> Bool -- | The module exports internal types along with their constructors. -- -- The rendering code relies on the newtype wrappers around Text -- to keep out invalid characters. Prefer to use the official interface -- if possible. module Addy.Internal.Types -- | Potential validation errors. data Error -- | A component of an email address may not start with the recorded prefix -- text. InvalidPrefixError :: Text -> Error -- | A component of an email address may not end with the recorded suffix -- text. InvalidSuffixError :: Text -> Error -- | A component of an email address contains invalid characters. InvalidCharactersError :: Text -> Error -- | A component of an email address does not meet the set length -- requirements. The values in this constructor are min, -- max, and actual. InvalidLengthError :: Int -> Int -> Int -> Error -- | The input to the address decoder was not a valid email address and -- produced the recorded error message. ParserFailedError :: Text -> Error -- | The representation of a complete email address. -- -- The parser preserves optional components such as the display name and -- comments. The rendering code can optionally include these optional -- elements when turning the address back into Text. data EmailAddr EmailAddr :: Maybe DisplayName -> LocalPart -> Domain -> [Comment] -> EmailAddr [_displayName] :: EmailAddr -> Maybe DisplayName [_localPart] :: EmailAddr -> LocalPart [_domain] :: EmailAddr -> Domain [_comments] :: EmailAddr -> [Comment] -- | Optional display name. Addresses in the name-addr format from -- RFC 5322 allow descriptive text to precede the address. This is -- commonly used in email messages to list the name of the address' -- owner. displayName :: Lens' EmailAddr (Maybe DisplayName) -- | The LocalPart of an email address usually references the -- destination mailbox on the Domain server. However, the content -- of the LocalPart can only be understood by the receiving -- Domain. localPart :: Lens' EmailAddr LocalPart -- | The Domain refers to the fully-qualified domain name that -- accepts mail for the associated LocalPart. See the -- documentation for the Domain type for more details. domain :: Lens' EmailAddr Domain -- | Addresses in both the name-addr and addr-spec -- formats support comments. comments :: Lens' EmailAddr [Comment] -- | Optional display name. Usually this is the name of the person who -- receives email at the associated address. -- --
-- Display Name <example@example.com> --newtype DisplayName DP :: Text -> DisplayName [displayNameText] :: DisplayName -> Text -- | The name of the mailbox on the associated Domain. newtype LocalPart LP :: Text -> LocalPart [localPartText] :: LocalPart -> Text -- | A fully-qualified domain name or an address literal. -- -- Most email addresses use a domain name. However, it's perfectly legal -- to use an AddressLiteral instead. data Domain Domain :: DomainName -> Domain DomainLiteral :: AddressLiteral -> Domain -- | Prism for working with domain names. _Domain :: Prism' Domain DomainName -- | Prism for working with domain literals. _DomainLiteral :: Prism' Domain AddressLiteral -- | A fully-qualified domain name which is made up of a list of host names -- (labels) separated by dots. newtype DomainName DN :: Text -> DomainName [domainNameText] :: DomainName -> Text -- | The name of one host component of a domain name. newtype HostName HN :: Text -> HostName [hostNameText] :: HostName -> Text -- | Iso for converting between domain names and a list of host names. -- --
-- >>> "gmail.uk.co" ^. _DomainName._HostNames & map (review _HostName) -- ["gmail","uk","co"] --_HostNames :: Iso' DomainName [HostName] -- | Address literals can be used instead of a domain name to direct mail -- to a specific IP address or other tagged address type. -- -- Example email addresses with address literals: -- --
-- example@[127.0.0.1] -- example@[IPv6:1111:2222:3333:4444:5555:6666:7777] -- example@[Just-some-text] --data AddressLiteral -- | A literal IP address as defined in RFC 5321 §4.1.3. The address can be -- in many formats so it is presented here in its parsed form. IpAddressLiteral :: IP -> AddressLiteral -- | RFC 5321 also defines a general address literal where a -- standardized tag precedes the address itself. The only -- information provided about the standardized tag is: -- --
-- Standardized-tag MUST be specified in a -- Standards-Track RFC and registered with IANA --TaggedAddressLiteral :: AddressTag -> Literal -> AddressLiteral -- | RFC 5322 defines a domain-literal as (roughly) a span of -- characters that are allowed in a domain name. The interpretation of -- those characters is left to "separate documents" such as RFC 5321. -- -- If an address literal cannot be parsed in one of the proceeding -- formats it is encoded as a Literal value. AddressLiteral :: Literal -> AddressLiteral -- | Prism for working with IP address literals. _IpAddressLiteral :: Prism' AddressLiteral IP -- | Prism for working with tagged address literals. _TaggedAddressLiteral :: Prism' AddressLiteral (AddressTag, Literal) -- | Prism for working with address literals. _AddressLiteral :: Prism' AddressLiteral Literal -- | A tag that can be used with a TaggedAddressLiteral. newtype AddressTag AT :: Text -> AddressTag [addressTagText] :: AddressTag -> Text -- | A literal address that can be used with a TaggedAddressLiteral -- or AddressLiteral. newtype Literal Lit :: Text -> Literal [literalText] :: Literal -> Text -- | A comment which may appear in an email address in a specific location. data Comment Comment :: CommentLoc -> CommentContent -> Comment -- | Prism for working with a Comment. _Comment :: Prism' Comment (CommentLoc, CommentContent) -- | Lens for working with comment locations. commentLoc :: Lens' Comment CommentLoc -- | Lens for working with comment contents. commentContent :: Lens' Comment CommentContent -- | The location where a comment was parsed or where it should be -- rendered. data CommentLoc -- | Just before the DisplayName. BeforeDisplayName :: CommentLoc -- | Just after the DisplayName but before the address. AfterDisplayName :: CommentLoc -- | Before the LocalPart of the address. BeforeLocalPart :: CommentLoc -- | After the Domain. AfterDomain :: CommentLoc -- | After the complete address. AfterAddress :: CommentLoc -- | Text that can appear in a comment. newtype CommentContent CC :: Text -> CommentContent [commentContentText] :: CommentContent -> Text instance GHC.Show.Show Addy.Internal.Types.DisplayName instance GHC.Base.Semigroup Addy.Internal.Types.DisplayName instance GHC.Classes.Eq Addy.Internal.Types.DisplayName instance GHC.Show.Show Addy.Internal.Types.LocalPart instance GHC.Base.Semigroup Addy.Internal.Types.LocalPart instance GHC.Classes.Eq Addy.Internal.Types.LocalPart instance GHC.Classes.Eq Addy.Internal.Types.Domain instance GHC.Show.Show Addy.Internal.Types.Domain instance GHC.Show.Show Addy.Internal.Types.DomainName instance GHC.Base.Semigroup Addy.Internal.Types.DomainName instance GHC.Classes.Eq Addy.Internal.Types.DomainName instance GHC.Show.Show Addy.Internal.Types.HostName instance GHC.Base.Semigroup Addy.Internal.Types.HostName instance GHC.Classes.Eq Addy.Internal.Types.HostName instance GHC.Classes.Eq Addy.Internal.Types.AddressLiteral instance GHC.Show.Show Addy.Internal.Types.AddressLiteral instance GHC.Show.Show Addy.Internal.Types.AddressTag instance GHC.Base.Semigroup Addy.Internal.Types.AddressTag instance GHC.Classes.Eq Addy.Internal.Types.AddressTag instance GHC.Show.Show Addy.Internal.Types.Literal instance GHC.Base.Semigroup Addy.Internal.Types.Literal instance GHC.Classes.Eq Addy.Internal.Types.Literal instance GHC.Classes.Eq Addy.Internal.Types.Comment instance GHC.Show.Show Addy.Internal.Types.Comment instance GHC.Show.Show Addy.Internal.Types.CommentContent instance GHC.Base.Semigroup Addy.Internal.Types.CommentContent instance GHC.Classes.Eq Addy.Internal.Types.CommentContent instance GHC.Classes.Eq Addy.Internal.Types.CommentLoc instance GHC.Show.Show Addy.Internal.Types.CommentLoc instance GHC.Classes.Eq Addy.Internal.Types.Error instance GHC.Show.Show Addy.Internal.Types.Error instance (GHC.Show.Show a, GHC.TypeLits.KnownSymbol n) => GHC.Show.Show (Addy.Internal.Types.RenamedShow n a) -- | Internal functions to render an EmailAddr to a Builder. module Addy.Internal.Render -- | Render mode. data Mode -- | Render the entire email address, including the optional display name -- and comments. Full :: Mode -- | Only render the simplest form of the email address. Only the -- LocalPart and Domain are rendered in this mode. Short :: Mode -- | Render an email address. render :: Mode -> EmailAddr -> Builder -- | Render the given address as text. renderToText :: Mode -> EmailAddr -> Text -- | Render an email address in addr-spec format. renderAddrSpec :: Mode -> EmailAddr -> Builder -- | Render a display name. renderDisplayName :: DisplayName -> Builder -- | Render comments that have the given CommentLoc. The comment -- location is also used to decide where to introduce white space. renderComments :: Mode -> CommentLoc -> [Comment] -> Builder instance GHC.Show.Show Addy.Internal.Types.EmailAddr -- | Internal data validation functions. module Addy.Internal.Validation -- | Validate a single host name. Each host name in a domain name (referred -- to as a label) must validate with this function. -- -- RFC 2181 §11 clearly states that there are no restrictions placed on -- which characters may appear in a label. However, due to legacy issues -- we enforce the rule from RFC 952 §1 that disallows hyphens as the -- first or last character of a label. -- -- RFC 5322 §3.4.1 restricts the characters that may appear in the domain -- component of an email address. Even though a DNS label does not -- impose such restrictions, in order to be a valid email address the -- label must only be composed of so-called atext characters or -- UTF8-non-ascii characters. -- -- Finally, RFC 2181 §11 restricts the length of a label to 63 bytes and -- the fully-qualified domain name to 255 bytes. RFC 6532 which extends -- the email syntax to allow UTF-8 encoded Unicode characters briefly -- states in §3.4 to continue using bytes, and not characters. It also -- states that Unicode text should be normalized (which we do). validateHostName :: Text -> Validation (NonEmpty Error) HostName -- | Validate a domain name. -- -- The domain name is split into host names (labels) and each label is -- validated with validateHostName. validateDomainName :: Text -> Validation (NonEmpty Error) DomainName -- | Validate and normalize the text content of the LocalPart of an -- email address. -- -- RFC 3696 §3 restricts the length of the local part to a maximum of 64 -- bytes. RFC 6532 extends the character set to include Unicode -- characters but maintains the length measurement as bytes and not -- characters. validateLocalPart :: Text -> Validation (NonEmpty Error) LocalPart -- | Validate the content of a DisplayName. -- -- There does not appear to be a limit on the length of the display name. -- For consistency and efficiency we limit it to 64 bytes, the same as -- the local part. validateDisplayName :: Text -> Validation (NonEmpty Error) DisplayName -- | Validate the Literal content of a domain literal. -- -- There does not appear to be a limit on the length of an address -- literal but for consistency with DNS labels we limit them to 63 bytes. validateLiteral :: Text -> Validation (NonEmpty Error) Literal -- | Validate the content of an AddressTag. Uses the same rules as -- validateLiteral. validateAddressTag :: Text -> Validation (NonEmpty Error) AddressTag -- | Validate the content of a comment. -- -- There does not appear to be a limit on the length of a comment. For -- consistency and efficiency we limit it to 64 bytes, the same as the -- local part. validateCommentContent :: Text -> Validation (NonEmpty Error) CommentContent -- | Validate an entire EmailAddr. This is used by the parser to -- validate rules that are not encoded in the various component parsers. validateEmailAddr :: EmailAddr -> Validation (NonEmpty Error) EmailAddr -- | Internal parsing functions. module Addy.Internal.Parser -- | Parsing mode. data Mode -- | Only support non-obsoleted addresses. Strict :: Mode -- | Include support for obsolete addresses. Lenient :: Mode -- | RFC 5322 atom. data Atom Atom :: Maybe CommentContent -> Text -> Maybe CommentContent -> Atom -- | An email address parser. parse :: Mode -> Parser EmailAddr -- | Run the parser and then validate the resulting address. parseWithMode :: Mode -> Text -> Either (NonEmpty Error) EmailAddr -- | Parse email addresses in the name-addr format. nameAddr :: Mode -> Parser EmailAddr -- | Parse email addresses in the addr-spec format. addrSpec :: Mode -> Parser EmailAddr -- | Parse the local-part of an email address. -- -- RFC 5322 §3.4.1 -- --
-- local-part = dot-atom / quoted-string / obs-local-part --localPartP :: Mode -> Parser (Maybe CommentContent, LocalPart) -- | Domain name parser. domainP :: Mode -> Parser (Domain, Maybe CommentContent) -- | Parse a display name. displayNameP :: Mode -> Parser Atom -- | An atom or quoted string. -- --
-- word = atom / quoted-string --word :: Mode -> Parser Atom -- | Parse an unquoted atom. -- --
-- atom = [CFWS] 1*atext [CFWS] --atom :: Mode -> Parser Atom -- | RFC 5322 dot-atom. dotAtom :: Mode -> Parser Atom -- | Strict dot-atom-lh from RFC 5322 errata. -- --
-- dot-atom-lh = [CFWS] dot-atom-text [FWS] --dotAtomLh :: Parser Atom -- | Strict dot-atom-rh from RFC 5322 errata. -- --
-- dot-atom-rh = [FWS] dot-atom-text [CFWS] --dotAtomRh :: Parser Atom -- | A quoted string. -- -- RFC5322 §3.2.4 -- --
-- qtext = %d33 / ; Printable US-ASCII -- %d35-91 / ; characters not including -- %d93-126 / ; "\" or the quote character -- obs-qtext -- -- qcontent = qtext / quoted-pair -- -- quoted-string = [CFWS] -- DQUOTE *([FWS] qcontent) [FWS] DQUOTE -- [CFWS] -- -- obs-qtext = obs-NO-WS-CTL ---- -- RFC 6532 §3.2 -- --
-- qtext =/ UTF8-non-ascii ---- -- RFC 5322 errata item 3135 -- https://www.rfc-editor.org/errata/eid3135 -- --
-- quoted-string = [CFWS] -- DQUOTE ((1*([FWS] qcontent) [FWS]) / FWS) DQUOTE -- [CFWS] ---- -- This is the rule we use since it's consistent with the text of the -- RFC. quoted :: Mode -> Parser Atom -- | Strict quoted-string-lh from RFC 5322 errata. quotedLh :: Parser Atom -- | Comments and folding white space. -- --
-- ctext = %d33-39 / ; Printable US-ASCII
-- %d42-91 / ; characters not including
-- %d93-126 / ; "(", ")", or "\"
-- obs-ctext
--
-- obs-ctext = obs-NO-WS-CTL
--
-- ccontent = ctext / quoted-pair / comment
--
-- comment = "(" *([FWS] ccontent) [FWS] ")"
--
-- CFWS = (1*([FWS] comment) [FWS]) / FWS
--
cfws :: Mode -> Parser CommentContent
instance GHC.Show.Show Addy.Internal.Parser.Atom
instance GHC.Show.Show Addy.Internal.Parser.Mode
instance GHC.Classes.Eq Addy.Internal.Parser.Mode
instance GHC.Base.Semigroup Addy.Internal.Parser.Atom
instance GHC.Base.Monoid Addy.Internal.Parser.Atom
-- | Email addressed are complicated, really complicated. This library
-- supports all standardized forms of email addresses, including those
-- with UTF-8 encoded Unicode characters. The standards used by this
-- library include:
--
-- -- >>> Addy.decode "my . email . addy@(WTF)example.com" -- Left (ParserFailedError "local part > quoted content > '\"': Failed reading: satisfy" :| []) ---- --
-- >>> Addy.decodeLenient "my . email . addy@(WTF)example.com" -- Right (EmailAddr "my.email.addy@example.com (WTF)") --decodeLenient :: Text -> Either (NonEmpty Error) EmailAddr -- | Encode an email address as text. This function produces the short form -- of an email address. That is, just the LocalPart and the -- Domain separated by @. encode :: EmailAddr -> Text -- | Encode a complete email address to text, including the optional -- display name and any comments. encodeFull :: EmailAddr -> Text -- | The representation of a complete email address. -- -- The parser preserves optional components such as the display name and -- comments. The rendering code can optionally include these optional -- elements when turning the address back into Text. data EmailAddr -- | Build an EmailAddr from a LocalPart and -- DomainName. emailAddr :: LocalPart -> DomainName -> EmailAddr -- | Build an EmailAddr from a LocalPart and an -- AddressLiteral. emailAddrLit :: LocalPart -> AddressLiteral -> EmailAddr -- | Optional display name. Addresses in the name-addr format from -- RFC 5322 allow descriptive text to precede the address. This is -- commonly used in email messages to list the name of the address' -- owner. displayName :: Lens' EmailAddr (Maybe DisplayName) -- | The LocalPart of an email address usually references the -- destination mailbox on the Domain server. However, the content -- of the LocalPart can only be understood by the receiving -- Domain. localPart :: Lens' EmailAddr LocalPart -- | The Domain refers to the fully-qualified domain name that -- accepts mail for the associated LocalPart. See the -- documentation for the Domain type for more details. domain :: Lens' EmailAddr Domain -- | Addresses in both the name-addr and addr-spec -- formats support comments. comments :: Lens' EmailAddr [Comment] -- | Optional display name. Usually this is the name of the person who -- receives email at the associated address. -- --
-- Display Name <example@example.com> --data DisplayName -- | Prism for working with display names. -- --
-- import Control.Lens ((^?), review) ---- -- To convert text into a DisplayName with content validation: -- --
-- >>> "Some Text" ^? _DisplayName -- Just (DisplayName "Some Text") -- -- >>> "Some\nText" ^? _DisplayName -- Nothing -- Validation failed. ---- -- To access the text content of a DisplayName: -- --
-- >>> review _DisplayName someDisplayName -- "Some Text" ---- -- Uses validateDisplayName to perform validation. _DisplayName :: Prism' Text DisplayName -- | Validate the content of a DisplayName. -- -- There does not appear to be a limit on the length of the display name. -- For consistency and efficiency we limit it to 64 bytes, the same as -- the local part. validateDisplayName :: Text -> Validation (NonEmpty Error) DisplayName -- | The name of the mailbox on the associated Domain. data LocalPart -- | Prism for working with the local part of an email address. -- --
-- import Control.Lens ((^?), review) ---- -- To convert text to a LocalPart with content validation: -- --
-- >>> "cockroach+mouse" ^? _LocalPart -- Just (LocalPart "cockroach+mouse") -- -- >>> "cockroach\nmouse" ^? _LocalPart -- Nothing -- Validation failed. ---- -- To access the text content of a LocalPart: -- --
-- >>> review _LocalPart someLocalPart -- "cockamouse" ---- -- Uses validateLocalPart to perform validation. _LocalPart :: Prism' Text LocalPart -- | Validate and normalize the text content of the LocalPart of an -- email address. -- -- RFC 3696 §3 restricts the length of the local part to a maximum of 64 -- bytes. RFC 6532 extends the character set to include Unicode -- characters but maintains the length measurement as bytes and not -- characters. validateLocalPart :: Text -> Validation (NonEmpty Error) LocalPart -- | A fully-qualified domain name or an address literal. -- -- Most email addresses use a domain name. However, it's perfectly legal -- to use an AddressLiteral instead. data Domain Domain :: DomainName -> Domain DomainLiteral :: AddressLiteral -> Domain -- | Prism for working with domain names. _Domain :: Prism' Domain DomainName -- | Prism for working with domain literals. _DomainLiteral :: Prism' Domain AddressLiteral -- | A fully-qualified domain name which is made up of a list of host names -- (labels) separated by dots. data DomainName -- | Prism for working with domain names. -- --
-- import Control.Lens ((^?), review) ---- -- To convert text to a DomainName with validation: -- --
-- >>> "gmail.com" ^? _DomainName -- Just (DomainName "gmail.com") -- -- >>> "too.many.dots." ^? _DomainName -- Nothing ---- -- To access the text content of a DomainName: -- --
-- >>> review _DomainName someDomainName -- "gmail.com" ---- -- Uses validateDomainName to perform validation. _DomainName :: Prism' Text DomainName -- | Validate a domain name. -- -- The domain name is split into host names (labels) and each label is -- validated with validateHostName. validateDomainName :: Text -> Validation (NonEmpty Error) DomainName -- | The name of one host component of a domain name. data HostName -- | Iso for converting between domain names and a list of host names. -- --
-- >>> "gmail.uk.co" ^. _DomainName._HostNames & map (review _HostName) -- ["gmail","uk","co"] --_HostNames :: Iso' DomainName [HostName] -- | Prism for working with host names (DNS labels). -- --
-- import Control.Lens ((^?), review) ---- -- To convert text to a host name with validation: -- --
-- >>> "com" ^? _HostName -- Just (HostName "com") -- -- >>> "com." ^? _HostName -- Nothing -- Validation failed. ---- -- To access the text content of a HostName: -- --
-- >>> review _HostName someHostName -- "com" ---- -- Uses validateHostName to perform validation. _HostName :: Prism' Text HostName -- | Validate a single host name. Each host name in a domain name (referred -- to as a label) must validate with this function. -- -- RFC 2181 §11 clearly states that there are no restrictions placed on -- which characters may appear in a label. However, due to legacy issues -- we enforce the rule from RFC 952 §1 that disallows hyphens as the -- first or last character of a label. -- -- RFC 5322 §3.4.1 restricts the characters that may appear in the domain -- component of an email address. Even though a DNS label does not -- impose such restrictions, in order to be a valid email address the -- label must only be composed of so-called atext characters or -- UTF8-non-ascii characters. -- -- Finally, RFC 2181 §11 restricts the length of a label to 63 bytes and -- the fully-qualified domain name to 255 bytes. RFC 6532 which extends -- the email syntax to allow UTF-8 encoded Unicode characters briefly -- states in §3.4 to continue using bytes, and not characters. It also -- states that Unicode text should be normalized (which we do). validateHostName :: Text -> Validation (NonEmpty Error) HostName -- | Address literals can be used instead of a domain name to direct mail -- to a specific IP address or other tagged address type. -- -- Example email addresses with address literals: -- --
-- example@[127.0.0.1] -- example@[IPv6:1111:2222:3333:4444:5555:6666:7777] -- example@[Just-some-text] --data AddressLiteral -- | A literal IP address as defined in RFC 5321 §4.1.3. The address can be -- in many formats so it is presented here in its parsed form. IpAddressLiteral :: IP -> AddressLiteral -- | RFC 5321 also defines a general address literal where a -- standardized tag precedes the address itself. The only -- information provided about the standardized tag is: -- --
-- Standardized-tag MUST be specified in a -- Standards-Track RFC and registered with IANA --TaggedAddressLiteral :: AddressTag -> Literal -> AddressLiteral -- | RFC 5322 defines a domain-literal as (roughly) a span of -- characters that are allowed in a domain name. The interpretation of -- those characters is left to "separate documents" such as RFC 5321. -- -- If an address literal cannot be parsed in one of the proceeding -- formats it is encoded as a Literal value. AddressLiteral :: Literal -> AddressLiteral -- | Prism for working with IP address literals. _IpAddressLiteral :: Prism' AddressLiteral IP -- | Prism for working with tagged address literals. _TaggedAddressLiteral :: Prism' AddressLiteral (AddressTag, Literal) -- | Prism for working with address literals. _AddressLiteral :: Prism' AddressLiteral Literal -- | A tag that can be used with a TaggedAddressLiteral. data AddressTag -- | Prism for working with the AddressTag for an -- AddressLiteral. -- --
-- import Control.Lens ((^?), review) ---- -- To convert text to an address tag with validation: -- --
-- >>> "IPv6" ^? _AddressTag -- Just (AddressTag "IPv6") -- -- >>> "[IPv6]" ^? _AddressTag -- Nothing -- Validation failed. ---- -- To access the text content of an AddressTag: -- --
-- >>> review _AddressTag someTag -- "tag" ---- -- Uses validateAddressTag to perform validation. _AddressTag :: Prism' Text AddressTag -- | Validate the content of an AddressTag. Uses the same rules as -- validateLiteral. validateAddressTag :: Text -> Validation (NonEmpty Error) AddressTag -- | A literal address that can be used with a TaggedAddressLiteral -- or AddressLiteral. data Literal -- | Prism for working with the literal text of an address literal. -- --
-- import Control.Lens ((^?), review) ---- -- To convert text to an address literal with validation: -- --
-- >>> "127.0.0.1" ^? _Literal -- Just (Literal "127.0.0.1") -- -- >>> "[]" ^? _Literal -- Nothing -- Validation failed. ---- -- To access the text content of a Literal: -- --
-- >>> review _Literal someLiteral -- "127.0.0.1" ---- -- Uses validateLiteral to perform validation. _Literal :: Prism' Text Literal -- | Validate the Literal content of a domain literal. -- -- There does not appear to be a limit on the length of an address -- literal but for consistency with DNS labels we limit them to 63 bytes. validateLiteral :: Text -> Validation (NonEmpty Error) Literal -- | A comment which may appear in an email address in a specific location. data Comment Comment :: CommentLoc -> CommentContent -> Comment -- | Prism for working with a Comment. _Comment :: Prism' Comment (CommentLoc, CommentContent) -- | Lens for working with comment locations. commentLoc :: Lens' Comment CommentLoc -- | Lens for working with comment contents. commentContent :: Lens' Comment CommentContent -- | The location where a comment was parsed or where it should be -- rendered. data CommentLoc -- | Just before the DisplayName. BeforeDisplayName :: CommentLoc -- | Just after the DisplayName but before the address. AfterDisplayName :: CommentLoc -- | Before the LocalPart of the address. BeforeLocalPart :: CommentLoc -- | After the Domain. AfterDomain :: CommentLoc -- | After the complete address. AfterAddress :: CommentLoc -- | Text that can appear in a comment. data CommentContent -- | Prism for working with the text content of a comment. -- --
-- import Control.Lens ((^?), review) ---- -- To convert text to a comment with validation: -- --
-- >>> "best email ever" ^? _CommentContent -- Just (CommentContent "best email ever") -- -- >>> "\n" ^? _CommentContent -- Nothing ---- -- To access the text content of the comment: -- --
-- >>> review _CommentContent someComment -- "super" ---- -- Uses validateCommentContent to perform validation. _CommentContent :: Prism' Text CommentContent -- | Validate the content of a comment. -- -- There does not appear to be a limit on the length of a comment. For -- consistency and efficiency we limit it to 64 bytes, the same as the -- local part. validateCommentContent :: Text -> Validation (NonEmpty Error) CommentContent