Sovite.Core.Routing (sovite v0.2.0)

Copy Markdown View Source

The routing configuration ([domains], [routing], and the next-hop settings of [delivery]) together with Sovite's routing tables in the database, and the address helpers shared by rewriting (Sovite.Core.Rewrite), recipient expansion (Sovite.Core.Recipients), and next-hop selection (Sovite.Core.Router).

Domain classes

Every recipient domain is in one class, set in the [domains] config section or with sovitectl domain:

  • :local - this server's own domains.
  • :aliased - every address must be an alias (sovitectl alias).
  • :hosted - mailboxes hosted here (sovitectl mailbox).
  • :relay - domains this server relays for, such as a backup MX.
  • :remote - everything else.

Summary

Functions

Adds an extension to the local part of address, unless it already has one.

Splits a list of addresses separated by commas or whitespace.

The class of domain (lower-case): from the [domains] config section, else from the domains in the database.

Splits the extension off a local part: "alice+lists" is {"alice", "+lists"} with delimiter "+". With several delimiter characters, the first one found counts. Returns {local, nil} without an extension.

Whether domain is one this server accepts mail for without relaying.

Looks up an address in tables, trying, in order

Builds the routing configuration from config, reading the routing tables from Sovite's database repo. Without a database (nil), there are no table entries.

Turns a list of IP addresses (at most one per family) into %{ipv4: ip, ipv6: ip}, leaving out missing families.

Splits an address into its local part and lower-cased domain. A bare local part ("postmaster") has domain nil.

The transport for domain class class (:local, :hosted, :relay, :remote).

Whether address is a usable mailbox: local@domain, or local@[literal].

Types

class()

@type class() :: :local | :aliased | :hosted | :relay | :remote

t()

@type t() :: %Sovite.Core.Routing{
  aliased_domains: term(),
  aliases: term(),
  always_bcc: term(),
  class_transports: term(),
  delimiter: term(),
  domain_cache: term(),
  hide_subdomains: term(),
  hide_subdomains_exceptions: term(),
  hosted_domains: term(),
  hostname: term(),
  local_domains: term(),
  local_recipients: term(),
  mailboxes: term(),
  moved_users: term(),
  recipient_bcc: term(),
  recipient_rewrites: term(),
  relay_auth: term(),
  relay_credentials: term(),
  relay_domains: term(),
  relayhost: term(),
  rewrite_headers: term(),
  sender_bcc: term(),
  sender_relayhosts: term(),
  sender_rewrites: term(),
  sender_source_addresses: term(),
  source_address: term(),
  transports: term()
}

Functions

add_extension(routing, address, ext)

@spec add_extension(t(), String.t(), String.t() | nil) :: String.t()

Adds an extension to the local part of address, unless it already has one.

addresses(value)

@spec addresses(String.t()) :: [String.t()]

Splits a list of addresses separated by commas or whitespace.

class(routing, domain)

@spec class(t(), String.t()) :: class()

The class of domain (lower-case): from the [domains] config section, else from the domains in the database.

extension(delimiter, local)

@spec extension(t() | String.t(), String.t()) :: {String.t(), String.t() | nil}

Splits the extension off a local part: "alice+lists" is {"alice", "+lists"} with delimiter "+". With several delimiter characters, the first one found counts. Returns {local, nil} without an extension.

hosted?(routing, domain)

@spec hosted?(t(), String.t()) :: boolean()

Whether domain is one this server accepts mail for without relaying.

lookup(routing, tables, address, opts \\ [])

@spec lookup(t(), Sovite.Core.Lookup.tables(), String.t(), keyword()) ::
  {:ok, String.t(), atom(), String.t() | nil} | :error | {:error, String.t()}

Looks up an address in tables, trying, in order:

  1. user+ext@domain
  2. user@domain
  3. user+ext and user, with local_part: true
  4. @domain, with catchall: true

Keys are lower-cased. Returns the value with how it matched: :address for the first key, otherwise :base, :local_part, or :catchall, and the extension, so the caller can propagate it.

new(config, repo \\ nil)

@spec new(Sovite.Core.Config.t(), Sovite.Core.Repo.t() | nil) :: t()

Builds the routing configuration from config, reading the routing tables from Sovite's database repo. Without a database (nil), there are no table entries.

source_address(ips)

@spec source_address([:inet.ip_address()]) :: %{
  optional(:ipv4 | :ipv6) => :inet.ip_address()
}

Turns a list of IP addresses (at most one per family) into %{ipv4: ip, ipv6: ip}, leaving out missing families.

split(address)

@spec split(String.t()) :: {String.t(), String.t() | nil}

Splits an address into its local part and lower-cased domain. A bare local part ("postmaster") has domain nil.

transport(routing, class)

@spec transport(t(), class()) :: Sovite.Core.Transport.t()

The transport for domain class class (:local, :hosted, :relay, :remote).

valid_address?(address)

@spec valid_address?(String.t()) :: boolean()

Whether address is a usable mailbox: local@domain, or local@[literal].