Skip to content

feat: Add Transactional_Email_Capability interface and Amazon SES core integration #723

@superdav42

Description

@superdav42

Summary

Add a new capability interface for transactional email delivery (distinct from the existing Email_Selling_Capability which provisions mailboxes). This enables the core plugin to manage how WordPress sends outbound email (password resets, WooCommerce notifications, admin alerts) on a per-site basis, with automatic domain verification.

Problem

Currently, transactional email delivery is configured at the server level (ssmtp/Postfix) and is invisible to the multisite platform. This creates several problems:

  1. From-address mismatch: All sites send from the server's configured address, not their own domain -- hurting deliverability and brand trust
  2. No domain verification automation: Adding a new site requires manual DNS record setup for SPF/DKIM
  3. No per-site sending control: Can't throttle, monitor, or disable sending per site
  4. Provider lock-in: Changing email providers requires server-level reconfiguration

Proposed Solution

1. New Transactional_Email_Capability interface

Location: inc/integrations/capabilities/interface-transactional-email-capability.php

This is a separate concern from Email_Selling_Capability (which provisions mailboxes). Transactional email is about delivery routing, not mailbox management.

interface Transactional_Email_Capability {
    public function verify_domain(string $domain): array;
    public function get_domain_verification_status(string $domain): array;
    public function get_domain_dns_records(string $domain): array;
    public function send_email(string $from, string $to, string $subject, string $body, array $headers = []): array;
    public function get_sending_statistics(string $domain, string $period = '24h'): array;
    public function set_sending_quota(string $domain, int $max_per_day): array;
    public function test_connection();
}

2. Hook into wp_mail per site

The core should provide a filter/action system that allows the active transactional email provider to intercept wp_mail() calls and route them through the configured provider, using the correct from-address for the current site's domain.

3. Domain lifecycle hooks

Fire events when domains are added/removed from the multisite so addons (email, domain seller) can react:

  • wu_domain_added -- trigger domain verification in SES
  • wu_domain_removed -- optionally clean up verified identity
  • wu_domain_verified -- domain DNS records confirmed

4. Settings UI

Admin settings page section for selecting and configuring the transactional email provider, similar to how host provider integrations work today.

Architecture Notes

  • The existing Integration base class and Integration_Registry should be reused
  • AWS SigV4 signing already exists in the WorkMail integration (Amazon_WorkMail_Integration::sign_request()) -- extract to a shared AWS_Signer trait or utility class for reuse by SES
  • The DNS_Provider_Interface in inc/integrations/host-providers/ can be leveraged to auto-create verification DNS records when the domain's DNS is managed by a supported provider (e.g., Cloudflare)

Acceptance Criteria

  • Transactional_Email_Capability interface defined with methods above
  • Domain lifecycle hooks (wu_domain_added, wu_domain_removed, wu_domain_verified) firing at appropriate points
  • wp_mail interception mechanism that routes through the active provider with correct from-address
  • Settings UI for provider selection and configuration
  • AWS SigV4 signing extracted to reusable utility (shared with WorkMail)
  • Documentation for addon developers to implement the interface

Related

  • Email addon: will implement Amazon_SES_Email_Selling (separate issue)
  • Domain seller addon: will hook wu_domain_added to auto-verify (separate issue)
  • Existing: Email_Selling_Capability (mailbox provisioning -- different concern)
  • Existing: DNS_Provider_Interface (can auto-create DNS records)

aidevops.sh v3.5.539 plugin for OpenCode v1.3.12 with claude-opus-4-6 in an interactive session.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions