# v5.3.4
## 10/31/2026

1. [](#bugfix)
    * [security] The security fixes below were found by Anthropic's OSS Scanner
    * [security] A form value longer than 64 KiB is now cut to that length before an email body is converted with `process_markdown`
    * [security] The Date header of an inbound email is now ignored when it is longer than 256 bytes, and the message is read as having no date
    * [security] Addresses that plugins pass to the email plugin are used as plain text, while the addresses in a form's `email` action and in the plugin settings can still use Twig such as `{{ config.plugins.email.to }}`

# v5.3.3
## 10/21/2026

1. [](#new)
    * **Newsletters can go through a different provider from the rest of the site.** A new **Newsletter Mail Engine** setting (`mailer.marketing_engine`) beside the mail engine: site mail such as order confirmations and password resets keeps using the mail engine, and anything marked as marketing goes through the newsletter engine instead. Left on "Same as the mail engine", which is the default, everything goes one way as before. A sender marks a message with `$message->marketing()`; `Email::marketingEngine()` answers the engine it will use and `Email::splitEngines()` whether the two differ. Built for a site that sends its own mail through Cloudflare Email Service, which allows transactional mail only, and its newsletters through Resend or SES
    * **A provider can say it is for transactional mail only.** `Capabilities` takes an optional `transactionalOnly`, for a provider whose terms allow receipts, password resets and notifications but not newsletters or other bulk mail, as Cloudflare Email Service's do. A newsletter add-on reads it and refuses to send a campaign through that transport. A transport plugin checks `property_exists()` before passing it, so it still loads beside an older Email plugin. Written up in `docs/providers.md`
1. [](#bugfix)
    * **The debug log no longer records credentials.** With debug on, the HTTP transports' whole request, headers included, and the SMTP AUTH exchange went into `logs/email.log`, which put every API key, token and SMTP password the site sends with into a log file. The `Authorization` header, the header-borne tokens providers use and the SMTP password are now replaced with `<redacted>` before anything is logged or returned by `getLastSendDebug()`

# v5.3.2
## 10/21/2026

1. [](#new)
    * **A provider can name a test address.** A transport plugin's provider class may now have `testRecipient(): ?string`, answering an address the provider's own documentation names as accepted, delivered to nobody and reported back as delivered, such as Resend's `delivered@resend.dev` or the SES mailbox simulator. A store testing its delivery webhook sends there, so the test reaches no real inbox and still produces the event it waits for. It is deliberately not on the `Provider` interface, because a new interface method would be a fatal error in every transport plugin not updated in the same release: consumers ask `method_exists()`, a plugin that has it still loads beside an older Email plugin, and a plugin without it simply has none. Written up in `docs/providers.md`, with the rule that only an address the provider documents counts

# v5.3.1
## 10/09/2026

1. [](#improved)
    * Updated the bundled Symfony Mailer and Mime to 5.4.52 and the IDN polyfill to 1.43.0, which include the fixes for their published security advisories. Thanks @bago [#196](https://github.com/getgrav/grav-plugin-email/issues/196)

# v5.3.0
## 09/24/2026

1. [](#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

# v5.2.1
## 09/15/2026

1. [](#bugfix)
    * **A form that drops every one of its recipients no longer does it in silence.** An address the plugin cannot parse is discarded, and when the `to` parameter produced nothing at all, `buildMessage()` skipped the call that sets the To header entirely — so the message left with no recipients, the form told the visitor it had been sent, and not one line was written to any log. Every discarded address is now reported to both `logs/email.log` and `logs/grav.log`, naming the parameter it came from, the value that could not be read (truncated, so a mailing list cannot fill the log) and whether anything usable was left. The report also names the cause, because in practice there is only one: a `Name <address>` value that has been through Twig's escape filter, written as `|e` or applied by autoescape, arrives as `John Doe &lt;john@example.com&gt;`, which is not an email address by any reading. Address parameters want `|raw`. Addresses that do parse are handled exactly as before, including a partial failure — those go out to whoever was left, and are logged too, since half a send is every bit as quiet as none of one. Reported by @thekenshow ([grav#3905](https://github.com/getgrav/grav/issues/3905))
    * **A form whose email could not be sent stops reading the mail server's refusal out to the visitor.** What went on the page was the transport's own words with a stop emoji in front of them, which is written for whoever set up the mail account and not for whoever filled in the contact form — it routinely names the server, names the account, and explains precisely why the credentials were rejected, to an anonymous stranger. The transport's text now goes to the Grav log, where the site owner will actually look for it, and the visitor is shown something a site can configure: an `error_message` on the email action, or the new **Form send failure message** setting in the plugin's Email Defaults, or failing both a translated "Your message could not be sent right now. Please try again in a few minutes." With Grav's debugger switched on the transport's text is appended to it anyway, on the grounds that anybody looking at the form with the debugger running is the person configuring it. Reported by @pboguslawski ([form#567](https://github.com/getgrav/grav-plugin-form/issues/567))

# v5.2.0
## 09/08/2026

1. [](#new)
    * **`bin/plugin email test-email` says why a send failed, and what the provider called it when one worked.** It answered "Problem sending email..." and nothing else, which is the least useful thing it could say about the one kind of failure only the provider can explain — an unverified sender, a token for the wrong server, an account still pending approval. It now prints the transport's own words and the HTTP response body beneath them, and on a successful send prints the provider's id for the message
    * **An SMTP send gets an id too, read off the transcript.** Symfony's `SmtpTransport` asks the server to take the message, reads the answer — `250 Message queued as 68bf1ca9e0d2f` — checks the response code and drops the line, so an SMTP store had no provider id at all. It also appends the whole conversation to the `SentMessage`, so the answer was still there to be read, and it is now. On a provider's own relay that id is the provider's: MailerSend documents the id in this line as the same one their webhooks report events under, and since their webhooks carry no headers, no metadata and not the `Message-ID` either, it is the only handle a store sending through them over SMTP will ever get. SMTP2GO and SendGrid answer the same way, and an Exim relay spells it `id=`. Only the final `250` is read, because the ones before it are answers about an address rather than about the message, and a server that accepts without naming — plain `250 2.0.0 Ok` — still answers null rather than having something invented from the line
    * The send log line carries the provider's id for the message, which is the first thing worth knowing when a delivery webhook cannot be matched to the message it is about
    * **`getLastSendId()` answers the provider's own id for the message just sent.** Every API transport already hands one back — Symfony's Resend, Postmark, SES, SendGrid, Mailgun and MailerSend transports all call `SentMessage::setMessageId()` with whatever their API returned — and this plugin was collecting it and dropping it on the floor, keeping only the debug string beside it. It matters because it is the same id that provider then names in its delivery webhooks, so it is the one string both ends are certain to agree on. Anything storing it can join a bounce or a delivery report back to the message it is about without needing the provider to echo a custom header, and without needing the `Message-ID` the message left with to survive the trip — which it often does not: a provider running on Amazon SES mints its own on the way out and reports that one. Null on a failed send and on a transport that answers no id at all

1. [](#bugfix)
    * **A transport that answers a send with the message's own id no longer has that recorded as the provider's id.** `Message-ID` is an identification header and Symfony answers those with a list of ids rather than a string, so the guard meant to catch this was casting an array and comparing an id against the word "Array" — it had never once fired. Mailgun's API answers a send with the id the message already had, in its wire form with the angle brackets on, so a store on Mailgun recorded its own `Message-ID` as Mailgun's id for the message; the delivery event that arrived then named a third string again, and the rung of the correlation ladder meant to be the most reliable matched nothing. Both halves are fixed: the header is read as the list it is, and the two ids are compared without the brackets, which are a transport's habit rather than a difference in the id. `getLastSendId()` answers null on a transport that only echoes, which is the honest answer and lets the match fall to the `Message-ID` rung that does work
    * **A transport that cannot be built no longer takes the whole site down with it.** The mailer is built on `onPluginsInitialized`, on every request, long before anything has decided whether this request sends an email — so a provider plugin that throws while naming its DSN does not produce a failed send, it produces a white screen on every page of the site. Including the admin, including the settings form where the missing field would have been filled in, leaving hand-editing YAML over SSH as the only way back. Found by saving the Mailgun settings with the domain still empty, which is an ordinary thing to do on the way to configuring it. Building the transport is now guarded: the reason goes to the Grav log, the site stays up, and the store gets an `UnusableTransport` that refuses messages with that reason attached. Deliberately not `null://`, which accepts everything and delivers nothing — a store whose transport is broken has to be told, because silently swallowing a customer's order confirmation is the worse of the two failures by a distance

# v5.1.0
## 09/05/2026

1. [](#new)
    * Email actions and plugins can now set custom headers on a message with a `headers` parameter, a map of header name to value, applied after everything else. The pair this was added for is `List-Unsubscribe` and `List-Unsubscribe-Post`, which together are RFC 8058 one-click unsubscribe: the unsubscribe button next to the sender name in Gmail and Outlook, and the thing a bulk sender is now expected to have. Setting a header that is already there replaces it, a value may be a list for a header that is allowed to repeat, and a name or value that cannot be written is skipped and logged rather than failing the whole send. Plugins building their own message can pass the same list to `applyHeaders()`, and can ask `Email::supportsParameter('headers')` first instead of comparing version numbers
    * A test suite, run with `tests/vendor/bin/phpunit` after `composer install` inside `tests/`. It installs into `tests/vendor` from its own `tests/composer.json`, so the `vendor` directory the plugin ships stays free of development packages
    * A provider contract under `classes/Providers/`, so that everything a mail provider knows about itself — how its delivery webhooks are verified and read, how a webhook is created from a pasted API key, what a sending domain's DNS has to say, and what its transport does to custom headers on the way out — lives in that provider's own `grav-plugin-email-<provider>` plugin rather than in whatever add-on happened to need the answer first. A transport plugin implements `Providers\Provider` and registers itself on the new `onEmailProviders` event; `Email::providers()` answers the registry, `Email::providerFor($engine)` and `Email::providerByKey($key)` find one, and a caller asks `Email::supportsFeature('providers')` first rather than comparing version numbers. A transport with no delivery API registers nothing, which is a complete answer: a store can then say plainly that the transport cannot report deliveries instead of showing a webhook address nothing will ever post to. Written up for plugin authors in `docs/providers.md`
    * `Email::buildMailerFor($engine)` builds a Symfony mailer for a named engine rather than only for the one the site is configured with, through the same transport builder, the same `onEmailTransportDsn` event and the same DSNs as before. Nothing sends through it yet; it is there so that a site which one day wants some of its mail to leave through a second provider has somewhere to ask for that mailer, without that day being the day the transport builder gets rewritten
    * `Providers\Event::$hard` now has a documented second meaning on a `dropped` event, which is the difference between a subscriber who is gone and one who happened to be on the list the morning the store ran out of quota. `hard = true` means the provider refused the address — it is on that provider's suppression list, or bounced, complained or unsubscribed there — and a store may treat it as permanent. `hard = false` or null means the provider refused this one message: a daily quota, a virus scan, content it did not like. The address is fine. `Event::isRefusedAddress()` is the question a suppression list should be asking, and `docs/providers.md` sets out which of each provider's refusals is which
    * `Providers\SendHeader` names the header a store stamps its send id into, so that every provider answers the same one and nothing has to hard-code a name. It is `X-Grav-Send-Id` unless the site sets `providers.send_header` in the Email plugin's configuration, or an add-on calls `SendHeader::override()` to name it for the request. The reading of it lives there too — out of a map of custom args or user variables, a `{name, value}` header list, or SES's message tags — because seven transport plugins were each about to keep their own copy of the same twenty lines. `SendHeader::metadataHeader()` is the Postmark twin, which is the same value under the `X-PM-Metadata-` prefix that is the only way metadata reaches a Postmark webhook

# v5.0.8
## 09/04/2026

1. [](#bugfix)
    * The help text under the From, To, CC, BCC and Reply-to fields showed the name-addr example as "Your Name `" in the new admin, which renders help as sanitised HTML and dropped `<email@address.org>` as an unknown tag. The example's angle brackets are now written as entities so the format the field accepts is actually shown

# v5.0.7
## 08/28/2026

1. [](#improved)
    * The Spanish translation now covers every string, up from two, and the messages asking you to configure a 'to' or 'from' address no longer name the opposite one. Thanks to @pmoreno-rodriguez

# v5.0.6
## 08/17/2026

1. [](#bugfix)
    * Email addresses with a stray space around them are no longer thrown away, so a `from`, `to`, `cc`, `bcc` or `reply_to` setting that ends in a space keeps working instead of failing with a confusing "An email must have a From or a Sender header" error.
    * An address setting containing nothing but spaces now tells you that address needs configuring, rather than failing later with that same confusing error.

# v5.0.5
## 08/05/2026

1. [](#bugfix)
    * [security] On Grav 2.0, email settings can no longer read your site, system or theme configuration directly, which was a way around the restriction added in 5.0.4 that already stopped them reading it through `config` ([GHSA-p597-crqc-m349](https://github.com/getgrav/grav/security/advisories/GHSA-p597-crqc-m349)). Requires Grav 2.0.16 or later, which is also where the underlying protection for email settings lives.

# v5.0.4
## 08/04/2026

1. [](#bugfix)
    * [security] On Grav 2.0, Twig in a form's email settings now runs under Grav's content sandbox, so someone who can only edit pages can no longer use an email action to run commands on the server ([GHSA-gh8j-q67c-j53f](https://github.com/getgrav/grav/security/advisories/GHSA-gh8j-q67c-j53f)). Requires Grav 2.0.16 or later.
    * Email settings can still read your site configuration and this plugin's own address settings, so `{{ config.site.emails.sales }}` and `{{ config.plugins.email.to }}` keep working, but they can no longer read your mail server password or any other plugin's settings.
    * Grav 1.7 has no Twig content sandbox, so email settings behave there exactly as they did before, and the plugin still runs on the PHP versions that line supports.

# v5.0.3
## 06/14/2026

1. [](#improved)
    * Email templates that fail to render (a Twig syntax error, or an unresolved include or extends) are now logged to the email and Grav logs instead of failing silently, so a broken template is much easier to track down.

# v5.0.2
## 06/08/2026

1. [](#improved)
    * Button links in HTML emails now keep their white text in email clients that force their own link color, by targeting the `a.btn-primary` and `a.btn-secondary` selectors with `!important`.

# v5.0.1
## 04/17/2026

1. [](improved)
    * Fixed compatiblity

# v5.0.0
## 04/17/2026

1. [](#new)
    * Added Grav 2.0 / Admin 2.0 support

# v4.2.2
## 12/10/2025

1. [](#bugfix)
    * Fixed `createAddress()` to gracefully handle empty or invalid email addresses instead of throwing RFC 2822 errors
    * Fixed Twig processing to bypass Grav 1.8's security filter for trusted email config (fixes issues with `{% include %}` and field names containing `mail`)

# v4.2.1
## 11/24/2025

1. [](#improved)
    * Added more details for HTTP error logs when using API-based email providers
    * Addressed a compatibility issue with Grav 1.8beta

# v4.2.0
## 08/25/2025

1. [](#new)
    * PHP 8.4 compatibility
1. [](#improved)
    * Vendor library updates

# v4.1.2
## 01/06/2025

1. [](#improved)
    * Updated to latest symfony libraries (`v5.4.45`)
    * Added a note about Google App Passwords for authentication in the README.md

# v4.1.1
## 10/28/2024

1. [](#improved)
  * Updated logging methods to support Monolog2+

# v4.1.0
## 04/09/2024

1. [](#improved)
   * Update vendor libraries for Mailer to latest `5.4` versions
   * When you send an email you can use `Email::getLastSendMessage()` and `Email::getLastSendDebug()` methods to get information about the email processing.

# v4.0.4
## 07/10/2023

1. [](#bugfix)
   * Fix for email file attachments using stream

# v4.0.3
## 06/29/2023

1. [](#improved)
   * Simplified the `Email::processRecipients()` logic for readability
1. [](#bugfix)
   * Fix an issue with 2 email addresses provided with 'just' email and no name [#176](https://github.com/getgrav/grav-plugin-email/issues/176)
   * Fix for blank subjectlines when using `Message::setSubject()` in Twig templates [getgrav/grav-plugin-login#299](https://github.com/getgrav/grav-plugin-login/issues/299)

# v4.0.2
## 06/27/2023

1. [](#bugfix)
   * some recipient handling improvements. e.g. missing `bcc_name` throwing error
   * Allow overriding of defaults with a form configuration.  Use `null` to remove default email configuration

# v4.0.1
## 05/20/2023

1. [](#bugfix)
   * Fixed a bug with Email 4.0 ignoring `template:` parameter when dealing with multiple body sections

# v4.0.0
## 05/09/2023

1. [](#new)
   * Migrated from `Swiftmailer` (which has been deprecated) to `Symfony/Mailer`, a more modern and extensible mailing library.
   * Built-in support for `SMTP`, `SMTPS`, `Sendmail` and `Native` (uses best solution per-platform) engines
   * Added ability to have 3rd party plugins that provide new engines (e.g. `SendGrid`, `MailJet`, etc.) with `SMTP`, `API` or `HTTPS` transports for faster and more reliable email sending
   * More flexible options for email formatting including RFC822 `name-addr` format (`Joe Bloggs <user@example.com>`) and simple arrays (`[user@example.com, Joe Bloggs]`)
   * Support `tags` and `metadata` in `Email::buildMessage()`
   * Two new events `onEmailEngines` and `onEmailTransportDsn` to facilitate the integration of custom engines via plugins

# v4.0.0-rc.4
## 02/27/2023
   
1. [](#bugfix)
   * Fixed for multiple recipients [#167](https://github.com/getgrav/grav-plugin-email/issues/167)
   * Fix for simple array format with names which wasn't working

# v4.0.0-rc.3
## 10/27/2022
   
1. [](#bugfix)
   * Fixed an issue with array based email address

# v4.0.0-rc.2
## 10/19/2022
   
1. [](#improved)
   * Set `sendmail` as default engine to provide better fallback for unsupported `mailer` option
   * Added info about available engine plugins in `README.md`

# v4.0.0-rc.1
## 10/05/2022
   
1. [](#new)
   * Migrated from `Swiftmailer` (which has been deprecated) to `Symfony/Mailer`, a more modern and extensible mailing library.
   * Built-in support for `SMTP`, `SMTPS`, `Sendmail` and `Native` (uses best solution per-platform) engines
   * Added ability to have 3rd party plugins that provide new engines (e.g. `SendGrid`, `MailJet`, etc.) with `SMTP`, `API` or `HTTPS` transports for faster and more reliable email sending
   * More flexible options for email formatting including RFC822 `name-addr` format (`Joe Bloggs <user@example.com>`) and simple arrays (`[user@example.com, Joe Bloggs]`)
   * Support `tags` and `metadata` in `Email::buildMessage()`
   * Two new events `onEmailEngines` and `onEmailTransportDsn` to facilitate the integration of custom engines via plugins

# v3.2.0
## 03/28/2022

1. [](#new)
    * Require **Grav 1.7.32** and **Form 6.0.0**
1. [](#improved)
    * Added access email message object inside the twig template file
2. [](#bugfix)
    * Fixed twig not being initialized when building an email message

# v3.1.5
## 01/03/2022

1. [](#improved)
   * Updated to Swiftmailer `v6.3.0` with PHP 8.1 compatibility [#157](https://github.com/getgrav/grav-plugin-email/issues/157)

# v3.1.4
## 11/16/2021

1. [](#improved)
    * Added second parameter to `Email::send()` to get failed recipients

# v3.1.3
## 07/19/2021

1. [](#improved)
   * Pass page variable to processed forms [#141](https://github.com/getgrav/grav-plugin-email/pull/141)
   * Email configuration available to templates [#152](https://github.com/getgrav/grav-plugin-email/pull/152)
   * New Event after eMail was sent [#151](https://github.com/getgrav/grav-plugin-email/pull/151)

# v3.1.2
## 04/06/2021

1. [](#new)
    * Added new `onEmailMessage` event to make object available for editing [#150](https://github.com/getgrav/grav-plugin-email/pull/150)

# v3.1.1
## 01/31/2021

1. [](#improved)
    * Latest vendor updates including SwiftMailer `6.2.5`
    * Updated CLI commands
    * Minor code cleanup 

# v3.1.0
## 12/02/2020

1. [](#improved)
    * Added support for `auth_mode` in SMTP engine [#101](https://github.com/getgrav/grav-plugin-email/pull/101)
    * Obfuscate the password shown in the CLI `test-email` command [#140](https://github.com/getgrav/grav-plugin-email/pull/140)

# v3.0.10
## 11/09/2020

1. [](#improved)
    * Tweaked default `base.html.twig` template to better support dark-mode clients
    * Latest vendor updates
1. [](#bugfix)
    * Add missing support for `template:` in body array
    * Added check to process markdown with `text/html` content type only

# v3.0.9
## 06/08/2020

1. [](#improved)
    * Disable password autocomplete in password field
    * Don't save empty string in password field [#134](https://github.com/getgrav/grav-plugin-email/issues/134)

# v3.0.8
## 04/27/2020

1. [](#improved)
    * Updated vendor library files
    * Use Grav's Parsedown class

# v3.0.7
## 03/05/2020

1. [](#improved)
    * Updated email validator library
1. [](#bugfix)
    * Fixed `Invalid resource theme://` on CLI command `test-email` on Grav 1.6.21 and later versions [#128](https://github.com/getgrav/grav-plugin-email/issues/128)

# v3.0.6
## 02/11/2020

1. [](#improved)
    * Updated email validator library

# v3.0.5
## 02/03/2020

1. [](#bugfix)
    * Fixed a date in changelog (no other changes)

# v3.0.4
## 01/17/2020

1. [](#improved)
    * Added ZOHO configuration example
    * Updated SwiftMailer library for PHP 7.4 support

# v3.0.3
## 08/16/2019

1. [](#new)
    * Support an array of multiple emails in `email:` form process
    * Allow form values in email templates 
1. [](#improved)
    * Added Twig blocks for `content` and `footer` in `email/base.html.twig` template
    * Updated `README.md` to reflect working setup for GMail 

# v3.0.2
## 05/09/2019

1. [](#new)
    * Requires Form Plugin v3.0.3
    * Added Russian translation [#113](https://github.com/getgrav/grav-plugin-email/pull/113)
1. [](#bugfix)
    * Better fix for missing attachments when sending an email using a form [form#333](https://github.com/getgrav/grav-plugin-form/issues/333)

# v3.0.1
## 04/15/2019

1. [](#improved)
    * Put a `try/catch` around email attachments and log any errors rather than hard fail
1. [](#bugfix)
    * Fixed missing attachments when sending an email using a form [form#333](https://github.com/getgrav/grav-plugin-form/issues/333)

# v3.0.0
## 04/11/2019

1. [](#new)
    * Added new `template:` to choose twig template option for email form processing
    * Moved `buildMessage()` and `parseAddressValue()` to Email object and made public
    * Refactored the `EmailUtils::sendEmail()` to take an array of params or the old param list
    * Switched to SwiftMailer v.6.1.3 (requires PHP7/Grav 1.6)
    * SwiftMailer 6.x compatibility fixes  
    * Updated various translations 
    * Added support for Email Queue with Scheduler support
    * Code cleanup, composer update
    * Added a new `clear-queue-failures` CLI command to flush out failed sends
1. [](#improved)
    * Added backlink for scheduler task
    * Added support for `environment` option to `flushqueue` CLI command 
    * Fixed mailtrap hostname in README.md
    * Disable autocomplete on SMTP `user` and `password` fields
    
# v2.7.2
## 01/25/2019

1. [](#improved)
    * Added default for `to` address
    * Updated EN language [#99](https://github.com/getgrav/grav-plugin-email/pull/99)
    * Updated UK language [#98](https://github.com/getgrav/grav-plugin-email/pull/98)
    * Updated RU language [#100](https://github.com/getgrav/grav-plugin-email/pull/100)
    * Updated to SwiftMailer v5.4.12
1. [](#bugfix)
    * Fixed `mailtrap` hostname    

# v2.7.1
## 12/05/2017

1. [](#new)
    * Added new `onEmailSend()` event hook before sending [#70](https://github.com/getgrav/grav-plugin-email/pull/70)
1. [](#improved)
    * Added examples of setting up Email plugin with various SMTP providers
    * Updated RU language [#60](https://github.com/getgrav/grav-plugin-email/pull/60)
    * Updated to SwiftMailer v5.4.8

# v2.7.0
## 10/26/2017

1. [](#improved)
    * Now uses a dedicated `logs/email.log` file when `debug: true`
    * Improved the README.txt file with examples, and troubleshooting
    * Changed default engine to `sendmail` as `mail` is deprecated and not functioning [swiftmailer#866](https://github.com/swiftmailer/swiftmailer/issues/866}

# v2.6.2
## 09/30/2017

1. [](#improved)
    * Removed extraneous files from vendor folder 

# v2.6.1
## 09/07/2017

1. [](#improved)
    * Improved the error message when missing `from` in the configuration
    * Silently catch malformed email exceptions

# v2.6.0
## 05/22/2017

1. [](#improved)
    * Inherit options from plugin configuration [#39](https://github.com/getgrav/grav-plugin-email/pull/39)
1. [](#bugfix)
    * Also process translation on the email subject [https://github.com/getgrav/grav-plugin-comments/issues/38](https://github.com/getgrav/grav-plugin-comments/issues/38)

# v2.5.3
## 01/03/2017

1. [](#improved)
    * Updated to SwiftMailer 5.4.5 [#45](https://github.com/getgrav/grav-plugin-email/issues/45)

# v2.5.2
## 12/13/2016

1. [](#new)
    * RC released as stable

# v2.5.2-rc.1
## 11/26/2016

1. [](#new)
    * Added a new `process_markdown` option for emails in forms
1. [](#improved)
    * Improved the `Utils::sendEmail()` method to take the email type as an option

# v2.5.1
## 10/19/2016

1. [](#improved)
    * CLI command will fallback to use the `to` from email plugin config if not provided
    * Explicit Composer based class loader to fix issues with class case

# v2.5.0
## 09/07/2016

1. [](#new)
    * Added a new `bin/plugin email test-email` CLI command
1. [](#improved)
    * Moved Email `Utils` class from Login to Email plugin
    * Provide a sample base `email/base.html.twig` template for emails
1. [](#bugfix)
    * Fix handling attachments with the updated file upload field

# v2.4.3
## 08/16/2016

1. [](#improved)
    * Added Russian translation
    * Updated Swiftmailer to 5.4.3 [#37](https://github.com/getgrav/grav-plugin-email/issues/37)

# v2.4.2
## 08/10/2016

1. [](#improved)
    * Added Croatian translation

# v2.4.1
## 07/14/2016

1. [](#improved)
    * Allow multiple email recipients (comma separated) [#31](https://github.com/getgrav/grav-plugin-email/issues/31)
    * Added Danish and Spanish translations

# v2.4.0
## 05/11/2016

1. [](#improved)
    * Now includes Swiftmailer v5.4.2 which introduces a number of bug fixes and improvements
1. [](#bugfix)
    * Correct `starttls` implementation, bundled in TLS

# v2.3.0
## 04/20/2016

1. [](#improved)
    * Added debug option to enable logging on SwiftMailer.
    * Updated SwiftMailer from v5.1.0 to v5.4.1.
    * Added an option in the Admin settings to enable `starttls`
1. [](#bugfix)
    * Correctly name TLS in the Admin settings, the label was `TTS` (but the value was correctly named `tls`)

# v2.2.0
## 02/05/2016

1. [](#new)
    * Allow to send attachments in forms
    * Added French translation
1. [](#improved)
    * Throw an exception when trying to send emails without a `from` or `to` parameters setup, to intercept less meaningful errors and provide a better description on how to fix the problem
    * Changed SMTP password in admin to use a password field instead of plain text

# v2.1.0
## 12/18/2015

1. [](#new)
    * Added missing `content_type` to email.yaml
    * Added default values for CC and BCC
 1. [](#improved)
    * Improved documentation of new email params in `README.md`
    * Moved config setting of `mailer.default` to `mailer.engine`

# v2.0.0
## 12/11/2015

1. [](#new)
    * Added support for from/sender name (Thomas Keitel)
    * Added support for message content type (Thomas Keitel)
    * Added support for reply addresses (Thomas Keitel)
    * Added support for CC/BCC (Thomas Keitel)
    * Added support for multiple body parts (Thomas Keitel)
1. [](#bugfix)
    * Fix email engine selection (z38)

# v1.0.0
## 11/20/2015

1. [](#bugfix)
    * Fix for issue with no body parameter specified

# v0.2.1
## 09/11/2015

1. [](#bugfix)
    * Fix onFormProcessed event

# v0.2.0
## 08/11/2015

1. [](#improved)
    * Disable `enable` in admin

# v0.1.0
## 08/04/2015

1. [](#new)
    * ChangeLog started...
