Class: Protege::EmailDomain

Inherits:
ApplicationRecord show all
Includes:
BroadcastableEmailDomain
Defined in:
app/models/protege/email_domain.rb

Overview

A mail domain the Protege engine is configured to receive email for.

Each domain owns a 2048-bit RSA keypair, generated automatically on create and stored as PEM in dkim_private_key_pem; the public half is derived on demand for the DKIM DNS record. The model exists to drive the domain show page, which surfaces the four DNS records an operator must publish before the domain can receive and authenticate mail: MX (inbound routing), SPF (envelope sender authorisation), DKIM (signing key), and DMARC (alignment policy). Rotating the keypair therefore requires republishing the DKIM TXT record.

Constant Summary

Constants included from BroadcastableEmailDomain

BroadcastableEmailDomain::STREAM

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BroadcastableEmailDomain

#broadcast_email_domain_created, #broadcast_email_domain_removed, #broadcast_email_domain_updated

Class Method Details

.receives?(address) ⇒ Boolean

Report whether Protege receives mail for the given address's domain — i.e. whether it belongs to a registered EmailDomain. Drives the Action Mailbox routing predicate (+Gateway.claims?+) so the engine claims only its own inbound mail; until a domain is added, nothing routes. Parsing is delegated to Gateway::Mail::Address; blank or malformed input is not ours.

Parameters:

  • address (String, nil)

    a recipient address from an inbound email

Returns:

  • (Boolean)

    true when the address's domain is one Protege receives for



51
52
53
54
55
# File 'app/models/protege/email_domain.rb', line 51

def receives?(address)
  exists?(domain: Gateway::Mail::Address.parse(address).domain)
rescue ArgumentError
  false
end

Instance Method Details

#dkim_dns_nameString

Return the DNS hostname for the DKIM TXT record: <selector>._domainkey.<domain>.

Returns:

  • (String)

    the fully qualified DKIM record name



63
64
65
# File 'app/models/protege/email_domain.rb', line 63

def dkim_dns_name
  "#{dkim_selector}._domainkey.#{domain}"
end

#dkim_public_key_base64String

Return the Base64-encoded DER public key for the DKIM TXT record value.

Derives the public key from the stored private PEM each call, so it always matches the current keypair.

Returns:

  • (String)

    the strict-Base64-encoded public key



73
74
75
76
# File 'app/models/protege/email_domain.rb', line 73

def dkim_public_key_base64
  key = OpenSSL::PKey::RSA.new(dkim_private_key_pem)
  Base64.strict_encode64(key.public_key.to_der)
end

#dkim_txt_recordString

Return the DKIM TXT record value published at #dkim_dns_name.

Returns:

  • (String)

    the DKIM record carrying the RSA public key



95
96
97
# File 'app/models/protege/email_domain.rb', line 95

def dkim_txt_record
  "v=DKIM1; k=rsa; p=#{dkim_public_key_base64}"
end

#dmarc_txt_recordString

Return the DMARC TXT record value published at _dmarc.<domain>.

Returns:

  • (String)

    a strict-alignment, reject-policy DMARC record



102
103
104
# File 'app/models/protege/email_domain.rb', line 102

def dmarc_txt_record
  "v=DMARC1; p=reject; adkim=s; aspf=s; rua=mailto:dmarc@#{domain}"
end

#mx_recordString

Return the MX record value pointing inbound mail at this server.

Returns:

  • (String)

    the MX record value, with priority 10



81
82
83
# File 'app/models/protege/email_domain.rb', line 81

def mx_record
  "10 #{domain}."
end

#spf_txt_recordString

Return the SPF TXT record value for the domain apex.

Returns:

  • (String)

    an SPF policy authorising the domain's MX hosts



88
89
90
# File 'app/models/protege/email_domain.rb', line 88

def spf_txt_record
  'v=spf1 mx ~all'
end

#to_provisioningHash

The minimal signing material the self-hosted MTA needs to sign this domain's outbound mail — the domain, its DKIM selector, and the private key. One entry in Gateway.mail_provisioning_manifest, which the app pushes to the mail accessory's control listener whenever a domain changes.

Returns:

  • (Hash)

    the domain's provisioning entry



113
114
115
# File 'app/models/protege/email_domain.rb', line 113

def to_provisioning
  { domain:, selector: dkim_selector, private_key_pem: dkim_private_key_pem }
end