MailAddress v0.3.0 MailAddress View Source
Functions to handle RFC5321 Mail Addresses.
The library implements functions for handling email addresses as specified mostly by RFC5321. A large chunk of the address syntax is implemented, with a few exceptions:
- Handling of general address literals in domains (IPv4 and IPv6 address literals are supported).
- Handling of internationalized addresses (UTF8, punycode etc).
Creating Addresses
Addresses may be created a number of ways:
%MailAddress{}
- this will create a null address.Calling
new/3
- this will directly assign a local and domain part.Calling
MailAddress.Parser.parse/2
- this will parse a string into an address.
Examples
iex> %MailAddress{}
#MailAddress<>
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> addr
#MailAddress<test@example.org>
iex> {:ok, addr, ""} = MailAddress.Parser.parse("test@example.org")
iex> addr
#MailAddress<test@example.org>
Modifying Addresses
Addresses can be modified by a number of functions, which return a new address with the appropriate update:
set_domain/3
- updates domain.set_local_part/3
- updates local part of address.
Querying Addresses
Addresses can be queryied for their components:
address_literal?/1
- checks if the address has an address literal domain set.address_literal/1
- returns address literal domain (ornil
if none).domain?/1
- checks if the address has a domain set.domain/1
- returns the address domain.local_part?/1
- checks if the address has a local part set.local_part/1
- returns the address local part.needs_quoting?/1
- checks if the address local part needs quoting.null?/1
- returns true if the address is null (no local or domain parts).
Comparing and Encoding Addresses
domains_equal?/2
- compares address domains.encode/2
- encodes address as string, taking care of quoting etc.equal?/2
- compares two addresses.local_parts_equal?/2
- compares address local parts.
Parsing Addresses
The module MailAddress.Parser contains parsing code.
MailAddress.Parser.parse/2
- parses a string into an address.MailAddress.Parser.valid?/2
- determines if address has valid syntax.
Specifying Options
The MailAddress.Options
struct is used to store options for configuring
the library. Checks are applied after every change/creation operation.
Protocols
The library implements the Inspect
and String.Chars
protocols for
MailAddress
structs.
The Inspect
protocol is used in the iex
shell and by inspect/2
to
pretty-print the MailAddress
struct contents.
The String.Chars
protocol enables a MailAddress
struct to be directly
converted into an encoded string.
Link to this section Summary
Types
Error return type - a tuple containing :error
and a reason string
Represents an IPv4 or IPv6 address
Success return type - a tuple containing :ok
and a MailAddress
struct
The MailAddress
struct
Functions
Address struct
Returns the decoded address literal domain (if any), or nil otherwise
Checks whether address has an address literal domain part
Applies checks and optional domain downcasing to given address using passed options
Returns the domain part of the address
Checks whether address has a domain part
Compares domain of given address with domain
(case-insensitively).
Returns true
if the domains are the same, or false
otherwise
Returns address safely encoded, optionally (and by default) bracketed
Checks whether addr_1
and addr_2
are the same.
The local parts are compared case sensitively, whilst the domain parts
are compare case insensitively
Returns the local part of the address
Checks whether address has local part set
Compares address local parts (case-sensitively).
The second parameter may be either a string or a MailAddress
struct.
Returns true
if the local parts are the same, or false
otherwise
Checks whether domain part of address is ‘localhost’, or the domain is an address literal and is [127.0.0.1] or [IPv6:::1]
Checks to see if the given string is “localhost” or equivalent ([127.0.0.1] or [IPv6:::1])
Checks whether the local part of the given address needs quoting
Creates a new MailAddress
setting both local and domain parts at
the same time using the provided (or default) options
Checks whether the address in null (no local part and no domain)
Sets the domain part of the address using the provided (or default) options
Sets the local part of the address using the provided (or default) options
Link to this section Types
Error return type - a tuple containing :error
and a reason string.
ip_address() :: :inet.ip4_address() | :inet.ip6_address()
Represents an IPv4 or IPv6 address.
Success return type - a tuple containing :ok
and a MailAddress
struct.
t() :: %MailAddress{ address_literal: nil | ip_address(), domain: String.t(), local_part: String.t(), needs_quoting: boolean() }
The MailAddress
struct.
Link to this section Functions
Address struct.
The struct SHOULD be treated as opaque
and not tampered with directly as it may change, and the needs_quoting
field is cached.
Callers should use the appropriate functions to get/set fields which ensures that everything remains in-sync and valid.
address_literal(MailAddress.t()) :: String.t()
Returns the decoded address literal domain (if any), or nil otherwise.
Examples
iex> MailAddress.address_literal(%MailAddress{})
nil
iex> {:ok, addr} = MailAddress.new("test", "[192.168.0.1]", %MailAddress.Options{allow_address_literal: true})
iex> MailAddress.address_literal(addr)
{192, 168, 0, 1}
address_literal?(MailAddress.t()) :: boolean()
Checks whether address has an address literal domain part.
Examples
iex> MailAddress.address_literal?(%MailAddress{})
false
iex> {:ok, addr} = MailAddress.new("test", "[192.168.0.1]", %MailAddress.Options{allow_address_literal: true})
iex> MailAddress.address_literal?(addr)
true
check(MailAddress.t(), MailAddress.Options.t()) :: {:ok, MailAddress.t()} | error()
Applies checks and optional domain downcasing to given address using passed options.
This function is automatically called as required by other functions
in the package, so doesn’t normally need to be called unless you
are messing with the MailAddress
struct directly (which isn’t
a good idea).
If successful, returns {:ok, new_address}
, otherwise returns
{:error, error_message}
.
Returns the domain part of the address.
Examples
iex> MailAddress.domain(%MailAddress{})
""
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> MailAddress.domain(addr)
"example.org"
Checks whether address has a domain part.
Examples
iex> MailAddress.domain?(%MailAddress{})
false
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> MailAddress.domain?(addr)
true
domains_equal?(MailAddress.t(), String.t() | MailAddress.t()) :: boolean()
Compares domain of given address with domain
(case-insensitively).
Returns true
if the domains are the same, or false
otherwise.
Examples
iex> {:ok, addr_1} = MailAddress.new("test", "example.org")
iex> {:ok, addr_2} = MailAddress.new("another", "example.org")
iex> {:ok, addr_3} = MailAddress.new("test", "localhost", %MailAddress.Options{allow_localhost: true})
iex> MailAddress.domains_equal?(addr_1, "example.org")
true
iex> MailAddress.domains_equal?(addr_2, "EXAMPLE.ORG")
true
iex> MailAddress.domains_equal?(addr_1, "something_else")
false
iex> MailAddress.domains_equal?(addr_1, addr_2)
true
iex> MailAddress.domains_equal?(addr_1, %MailAddress{})
false
iex> MailAddress.domains_equal?(addr_3, "localhost")
true
iex> MailAddress.domains_equal?(addr_3, "[127.0.0.1]")
true
iex> MailAddress.domains_equal?(addr_3, "[IPv6:::1]")
true
encode(MailAddress.t(), boolean()) :: String.t()
Returns address safely encoded, optionally (and by default) bracketed.
Examples
iex> MailAddress.encode(%MailAddress{}, false)
""
iex> MailAddress.encode(%MailAddress{}, true)
"<>"
iex> {:ok, addr, ""} = MailAddress.Parser.parse("test@example.org")
iex> MailAddress.encode(addr, true)
"<test@example.org>"
iex> {:ok, addr, ""} = MailAddress.Parser.parse("\"@test\"@example.org")
iex> MailAddress.encode(addr, true)
"<\"\\@test\"@example.org>"
equal?(MailAddress.t(), MailAddress.t()) :: boolean()
Checks whether addr_1
and addr_2
are the same.
The local parts are compared case sensitively, whilst the domain parts
are compare case insensitively.
Examples
iex> {:ok, addr_1} = MailAddress.new("test", "example.org")
iex> {:ok, addr_2} = MailAddress.new("test", "ExAmPlE.ORG")
iex> MailAddress.equal?(addr_1, addr_2)
true
iex> {:ok, addr_3} = MailAddress.new("fred", "ExAmPlE.ORG")
iex> MailAddress.equal?(addr_1, addr_3)
false
local_part(MailAddress.t()) :: String.t()
Returns the local part of the address.
Examples
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> MailAddress.local_part(addr)
"test"
local_part?(MailAddress.t()) :: boolean()
Checks whether address has local part set.
Examples
iex> MailAddress.local_part?(%MailAddress{})
false
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> MailAddress.local_part?(addr)
true
local_parts_equal?(MailAddress.t(), MailAddress.t()) :: boolean()
Compares address local parts (case-sensitively).
The second parameter may be either a string or a MailAddress
struct.
Returns true
if the local parts are the same, or false
otherwise.
Examples
iex> {:ok, addr_1} = MailAddress.new("test", "example.org")
iex> {:ok, addr_2} = MailAddress.new("test", "example.com")
iex> MailAddress.local_parts_equal?(addr_1, addr_2)
true
iex> MailAddress.local_parts_equal?(addr_1, "test")
true
iex> MailAddress.local_parts_equal?(addr_2, "TEST")
false
Checks whether domain part of address is ‘localhost’, or the domain is an address literal and is [127.0.0.1] or [IPv6:::1].
Examples
iex> {:ok, addr_1} = MailAddress.new("test", "example.org")
iex> MailAddress.localhost?(addr_1)
false
iex> {:ok, addr_2} = MailAddress.new("test", "localhost", %MailAddress.Options{allow_localhost: true})
iex> MailAddress.localhost?(addr_2)
true
iex> {:ok, addr_3} = MailAddress.new("test", "[127.0.0.1]", %MailAddress.Options{allow_address_literal: true, allow_localhost: true})
iex> MailAddress.localhost?(addr_3)
true
iex> {:ok, addr_4} = MailAddress.new("test", "[192.168.0.1]", %MailAddress.Options{allow_address_literal: true, allow_localhost: true})
iex> MailAddress.localhost?(addr_4)
false
iex> {:ok, addr_5} = MailAddress.new("test", "[IPv6:::1]", %MailAddress.Options{allow_address_literal: true, allow_localhost: true})
iex> MailAddress.localhost?(addr_5)
true
Checks to see if the given string is “localhost” or equivalent ([127.0.0.1] or [IPv6:::1]).
Examples:
iex> MailAddress.localhost_string?("test")
false
iex> MailAddress.localhost_string?("LOCALHOST")
true
iex> MailAddress.localhost_string?("[127.0.0.1]")
true
iex> MailAddress.localhost_string?("[127.0.0.1")
false
iex> MailAddress.localhost_string?("[192.168.0.1]")
false
iex> MailAddress.localhost_string?("[IPv6:::1]")
true
needs_quoting?(MailAddress.t()) :: boolean()
Checks whether the local part of the given address needs quoting.
The needs_quoting
flag on the address is updated when the address
is changed, so calling this function is inexpensive.
new(String.t(), String.t(), MailAddress.Options.t()) :: {:ok, MailAddress.t()} | error()
Creates a new MailAddress
setting both local and domain parts at
the same time using the provided (or default) options
.
NOTE: the local part isn’t parsed - it is just checked to ensure that it only contains valid characters. This means that the local part should be raw rather than quoted form.
Returns either {:ok, new_address}
or {:error, error_reason}
.
Examples
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> addr
#MailAddress<test@example.org>
iex> {:ok, addr} = MailAddress.new("@test", "example.org")
iex> addr
#MailAddress<"\@test"@example.org>
iex> MailAddress.new("test", "example.org!")
{:error, "invalid domain"}
Checks whether the address in null (no local part and no domain).
Examples
iex> MailAddress.null?(%MailAddress{})
true
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> MailAddress.null?(addr)
false
iex> {:ok, addr} = MailAddress.new("", "", %MailAddress.Options{allow_null: true})
iex> MailAddress.null?(addr)
true
set_domain(MailAddress.t(), String.t(), MailAddress.Options.t()) :: {:ok, MailAddress.t()} | error()
Sets the domain part of the address using the provided (or default) options.
Returns either {:ok, new_address}
or {:error, error_reason}
.
Examples
iex> {:ok, addr} = MailAddress.set_domain(%MailAddress{}, "test", %MailAddress.Options{allow_null_local_part: true})
iex> MailAddress.domain(addr)
"test"
iex> {:ok, addr} = MailAddress.new("test", "example.com")
iex> MailAddress.domain(addr)
"example.com"
iex> {:ok, addr} = MailAddress.set_domain(addr, "example.org")
iex> MailAddress.domain(addr)
"example.org"
set_local_part(MailAddress.t(), String.t(), MailAddress.Options.t()) :: {:ok, MailAddress.t()} | error()
Sets the local part of the address using the provided (or default) options.
NOTE: the local part isn’t parsed - it is just checked to ensure that it only contains valid characters, consequently it should be in raw unquoted format.
Returns either {:ok, new_address}
or {:error, error_reason}
.
Examples
iex> {:ok, addr} = MailAddress.set_local_part(%MailAddress{}, "test", %MailAddress.Options{require_domain: false})
iex> MailAddress.local_part(addr)
"test"
iex> MailAddress.set_domain(%MailAddress{}, "test", %MailAddress.Options{allow_null_local_part: false})
{:error, "local part can't be null"}
iex> {:ok, addr} = MailAddress.new("test", "example.org")
iex> MailAddress.local_part(addr)
"test"
iex> {:ok, addr} = MailAddress.set_local_part(addr, "other")
iex> MailAddress.local_part(addr)
"other"