github getgrav/grav-plugin-email 5.3.0

9 hours ago

New

  • Inbound mail. A plugin that wants to read mail sent to a site — a helpdesk turning replies into ticket updates, a forum taking posts by email — now has one place to ask. Providers\Inbound\InboundGateway::receive() takes a receiver key, the request and that receiver's config, and runs the same four steps for every provider in the same order: find the receiver (404), check the size against the receiver's limit and the caller's (413, before any verification work), verify (401), and parse, which never throws. What comes back is an InboundResult holding the verdict, the HTTP status to answer with, and the messages. Each message is an InboundMessage with every field a consumer needs already normalised: message ids without brackets and lower-cased, the envelope recipient kept apart from the visible To so a support+token@ address survives, the receiving server's SPF, DKIM and DMARC verdicts read from Authentication-Results, and attachments with their inline cid: ids. Ask Email::supportsFeature('inbound') first; it is true on PHP 8.1 and later, like the rest of the provider contract
  • A provider plugin receives mail by implementing InboundCapable on the provider class it already registers. It is a separate interface rather than a new method on Provider, because every transport plugin implements Provider today and a new method there would be a fatal error in each one not updated in the same release. The rules are the delivery-report rules — authenticate before acting, over the raw bytes wherever the scheme signs raw bytes; parse() never throws and does no network I/O — plus fetch() for providers that send only metadata, which a consumer runs later from its own worker. Written up in docs/providers.md, which also refines the delivery-report rule to the same wording, since SNS and Mailgun sign inside the payload rather than over it
  • Two receivers that need no provider account at all. cloudflare takes each message from a free Cloudflare Email Routing Worker, byte for byte, signed end to end with an HMAC over the raw body, a timestamp and a 300-second window. generic is the same scheme for a Postfix pipe, a forwarder or a cron job. docs/inbound-cloudflare.md has the Worker source, the dashboard steps (including the Subaddressing setting that plus addresses need), Cloudflare's size and CPU limits, and a shell and a PHP sender, all checked against the real verifier
  • An IMAP client that does not need ext/imap, which left PHP core in 8.4 and was never on most hosts anyway. Inbound\Imap\ImapMailbox connects over implicit TLS or STARTTLS (never falling back to plain text), logs in, finds new mail by UID with UIDVALIDITY tracking, downloads it without marking it read, and marks it \Seen and moves it once the caller has stored it — with UID MOVE where the server has it and copy, delete and expunge where it does not. Messages over a size limit are reported without being downloaded, and every failure says whether it was the credentials, the network or the server. For Gmail with an app password and most hosting mailboxes; AUTHENTICATE XOAUTH2 has its place reserved for later
  • A MIME parser with no dependencies. Every maintained MIME library for PHP brings packages Grav core also ships at its own version (guzzlehttp/psr7, pimple/pimple, psr/container) or a dependency-injection container, and Grav loads every plugin's autoloader into one process. Providers\Inbound\MimeParser reads what received mail needs — encoded-word headers, nested multiparts, quoted-printable and base64, charsets (ISO-8859-1 read as Windows-1252, the way mail clients do), RFC 2231 filenames, inline images, forwarded messages kept whole as attachments, delivery reports — and never throws. Tested against Gmail, Outlook (with a winmail.dat) and Apple Mail replies, Latin-1 and Windows-1252 mail, a bounce, an out-of-office and a forward

Don't miss a new grav-plugin-email release

NewReleases is sending notifications on new releases.