# `ExEmail`
[🔗](https://github.com/synchronal/ex_email/blob/main/lib/ex_email.ex#L1)

`ExEmail` implements a parser and validator for email addresses according to the
ABNF rules defined in the following RFCs:

- [RFC5321 - Simple Mail Transfer Protocol](https://tools.ietf.org/rfc/rfc5321.txt)
- [RFC6531 - SMTP Extension for Internationalized](https://tools.ietf.org/rfc/rfc6531.txt)
- [RFC6532 - Internationalized Email Headers](https://tools.ietf.org/rfc/rfc6532.txt)

When parsing emails addressed to IP addresses, the domain part is parsed via the rules
defined in
[RFC3986: Uniform Resource Identifier (URI): Generic Syntax](https://tools.ietf.org/rfc/rfc3986.txt).

## Notes

- `ExEmail` is a reimplementation of [`:email_validator`](https://hex.pm/packages/email_validator)
  in Elixir. It's a fantastic library.
- ABNF rules are compiled using `AbnfParsec`. Because it's built on top of `NimbleParsec`,
  the ABNF shipped with this library differs from the relevant RFCs in specific ways. ABNF
  assumes that when a rule defines multiple choices, that each choice can be attempted, and
  then backtracked to the last matching rule; `NimbleParsec` does not support backtracking,
  so rules must be defined such that the most appropriate rule is most likely to be matched
  first.

# `domain_part`

```elixir
@type domain_part() :: String.t()
```

# `local_part`

```elixir
@type local_part() :: String.t()
```

# `t`

```elixir
@type t() :: {local_part(), domain_part()}
```

A tuple of the local and domain parts of an email address; parsing the address
`alice@example.com` returns `{"alice", "example.com"}`.

# `parse`

```elixir
@spec parse(String.t()) :: {:ok, t()} | {:error, ExEmail.Error.t()}
```

Parses an email address into a tuple of `{:ok, {local_part, domain_part}}`, or
`{:error, ExEmail.Error.t()}`.

## Examples

``` elixir
iex> ExEmail.parse("a@example.com")
{:ok, {"a", "example.com"}}
iex> ExEmail.parse("a@[127.0.0.1]")
{:ok, {"a", "[127.0.0.1]"}}
iex> ExEmail.parse("a@[IPv6:::1]")
{:ok, {"a", "[IPv6:::1]"}}

iex> ExEmail.parse("@example.com")
{:error, ExEmail.Error.new("parse error", "@example.com")}
```

# `validate`

```elixir
@spec validate(String.t()) :: :ok | {:error, ExEmail.Error.t()}
```

Validates the format of an email address, returning either `:ok` or a
tuple of `{:error, ExEmail.Error.t()}`.

## Examples

``` elixir
iex> ExEmail.validate("a@example.com")
:ok

iex> ExEmail.validate("@example.com")
{:error, ExEmail.Error.new("parse error", "@example.com")}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
