MailAddress v0.1.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 address literals in domains (e.g. [127.0.0.1]).
  • 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:

Querying Addresses

Addresses can be queryied for their components:

  • 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

Parsing Addresses

The module MailAddress.Parser contains parsing code.

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

Success return type - a tuple containing :ok and a MailAddress struct

t()

The MailAddress struct

Functions

Address struct

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’

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

Link to this type error() View Source
error() :: {:error, String.t()}

Error return type - a tuple containing :error and a reason string.

Link to this type success() View Source
success() ::
  {:ok, %MailAddress{domain: term(), local_part: term(), needs_quoting: term()}}

Success return type - a tuple containing :ok and a MailAddress struct.

Link to this type t() View Source
t() :: %MailAddress{
  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.

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"
Link to this function domain?(mail_address) View Source
domain?(MailAddress.t()) :: boolean()

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
Link to this function domains_equal?(arg1, domain) View Source
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> 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
Link to this function encode(addr, bracket \\ true) View Source
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>"

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
Link to this function local_part(mail_address) View Source
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"
Link to this function local_part?(mail_address) View Source
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
Link to this function local_parts_equal?(arg1, local_part) View Source
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
Link to this function localhost?(mail_address) View Source
localhost?(MailAddress.t()) :: boolean()

Checks whether domain part of address is ‘localhost’.

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
Link to this function needs_quoting?(mail_address) View Source
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.

Link to this function new(local, domain, options \\ %MailAddress.Options{}) View Source

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
Link to this function set_domain(addr, domain, options \\ %MailAddress.Options{}) View Source
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"
Link to this function set_local_part(addr, local, options \\ %MailAddress.Options{}) View Source
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"