4.3.0 - 5th Nov 2026
Send queue with retry for failed deliveries
Until now, a recipient to whom a mail could not be delivered was treated like a recipient who got the mail. There was no retry, and failed deliveries were only visible in the log of your mail server.
Failed deliveries are now written to a send queue and retried with increasing waiting times (1 minute, 5 minutes, 15 minutes, 1 hour, then every 4 hours). Permanent errors (SMTP reply code 5xx) are not retried, the recipient is marked as failed right away. After 20 attempts (configurable) a recipient is marked as failed for good.
- The module Mail > Queue shows waiting and failed recipients with the error message, the number of attempts and the time of the next attempt. The status is shown as an icon. You can send again or delete an entry after a confirmation.
- The email address of a delivery can be corrected before it is sent again. This function is a feature flag and disabled by default. Enable the new extension setting enableEmailCorrection (tab "feature") to use it.
- Recipients that failed for good get an additional entry with the response type "failed" in the mail log, with the SMTP code as return code. They are counted in the mail report. If such a recipient is delivered later, the entry is removed and the delivery is counted as sent.
- The list is refreshed automatically. The interval is set by the new page TSconfig setting undeliveredRefreshRate (5 seconds by default, 0 turns it off), which can also be changed in the configuration dialog of the queue module. Only a small request runs each cycle, the list is reloaded when it has changed. It is not replaced while an email address is being edited.
- The correction of an address only applies to this delivery (and needs the feature flag). The new PSR-14 event RecipientEmailCorrectedEvent makes it possible to apply it to the recipient record (tt_address, fe_users and so on) as well.
- The retry runs after each cycle of
mail:. You can also run it more often with the new commandmass- mailing mail:.retry- failed
See Send queue for details.
Alerting by webhook and email
New extension settings under the tab "queue":
- alertWebhookUrl: An HTTPS address that is called when the
queue turns unhealthy, and when it is healthy again. The request is a JSON POST with a
textfield, so a Slack incoming webhook works as it is. - alertThresholdMinutes and notifyOnRecovery control when the webhook is called.
- opsNotificationEmail: An email address that is notified for every recipient that failed for good.
Both are disabled as long as the settings are empty.
No overlapping send runs
mail: and mail: now share a lock. If a run is still active when the next one
starts, the new run ends immediately. This prevents duplicate mails, for example if a scheduler task takes longer than
its interval.
send-per-cycle is a limit for the whole run
The number of mails that are sent per cycle was counted per recipient source, so a mail with several recipient groups of different sources could send more mails per cycle than configured. The limit now applies to the whole run.
Manual delivery is switched off by default
The box with the button "Start sending manually" is only shown in the queue module, if "Send per click" in the configuration dialog of the module (sendPerCycle) is greater than 0. The dialog now accepts 0. The action behind the button refuses to run as well, if the value is 0, so it cannot be called by url either.
The default of "Send per click" changed from 50 to 0. This means, the manual delivery is switched off by default and
mails are only sent by the scheduler or the command mail:.
Important
If you did not save "Send per click" for your mail folder before, the box "Manual delivery" is not shown anymore after the update. To get it back, open the configuration dialog of the queue module (gear icon) and set "Send per click" to a value greater than 0, for example 50. A value that was saved before is kept.
Module is reloaded after saving a configuration dialog
If you changed a value in the configuration dialog of the queue module (or of the wizard) and saved it, the module below the dialog still showed the old values until the page was reloaded manually. For example the number of mails in the text of the manual delivery stayed the same. The module is now reloaded automatically when the dialog closes after saving. Closing the dialog without saving does not reload anything.
Note instead of an empty table in the queue module
If the mail queue is empty, the queue module now shows an info box with the text "The mail queue is empty" instead of a table with a single row. The box disappears by itself as soon as a mail is in the queue, also if another user scheduled it, or if there are failed deliveries in the retry queue. It appears again when the queue is empty. The check uses the interval refreshRate, the failed deliveries are checked with undeliveredRefreshRate.
Class attributes in the mail: keep the ones that are still needed
The class attributes of a mail are removed after the CSS has been inlined (remove, enabled by
default). This also removed the classes which are still needed by CSS rules that cannot be inlined, so a rule like
.body a: never applied.
-
The new option
removekeeps exactly the classes that are still referenced by such rules and removes all others. Example:Class Attributes. smart = 1 mail.10.removeClassAttributes = 1 mail.10.removeClassAttributes.smart = 1Copied! removekeeps the class attribute of the given tags,Class Attributes. keep On Tags removekeeps the given classes on all other elements. Both can be combined withClass Attributes. keep Classes smart.- The same is available in the Fluid template with the new arguments
remove,Class Attributes keep,On Tags keepandClasses smartof the EmogrifyViewHelper.Class Removal - Fix: The class was only removed from elements which had another attribute.
<div class="body">kept its class. The class attributes are now removed from every element. If your styles depended on a class that stayed by accident, add it withkeep.Classes - New options of the CSS inliner for the content object
EMOGRIFIER:addandExcluded Css Selector remove. They requireExcluded Css Selector pelago/7.3 or higher, the extension now requires this version.emogrifier Emogrifierhas strict parameter types now (Utility:: emogrify () string,string,bool,array) and does not acceptnullfor the HTML and the CSS anymore. This only affects your own code, which calls the method directly.
Warning
Do not assign your own CSS to mail. or mail.. These indexes are used by the
extension, your CSS replaces its styles and the mail loses e.g. its container width and padding. Use a free index like
mail..
See EMOGRIFIER and SCSS.
Improved detection of returned mails
Several users reported that returned mails (bounces) got a wrong reason and showed up in the wrong category of the report module. The detection is rewritten:
- The type and the reason are taken from the delivery status notification (RFC 3464) of the mail server, which carries the enhanced status code (for example 5.1.1 for an unknown recipient, 5.2.2 for a full mailbox). Only returned mails without a notification are classified by the text, in a defined order (for example "User unknown" counts before "Recipient address rejected").
- The quoted original of your mailing is not searched anymore. Before, words like "quota exceeded" in a newsletter could decide about the category of a returned mail.
- Rejections by a spam filter or a policy (status 5.7.x, "access denied", "relay denied") are no longer reported as "Recipient unknown". They have their own category "Blocked by policy or spam filter".
- Temporary problems (status 4.x.x, greylisting) are separated as "Temporary problems" and are not counted as permanent failures. A button "Disable returned recipients" only affects permanent bounces and no longer affects policy rejections and temporary problems.
- Returned mails with an unknown reason are stored now. Before they could get lost, because the reason was written as
-1into an unsigned column, which failed on databases in strict mode. The message stayed in the mailbox and was read again with every run. - Auto replies (out of office) and delivery receipts are ignored. The text is decoded (quoted-printable, base64, charsets), several recipients in one notification are handled and a recipient is counted once per mailing.
- The
mail:command continues after an error in one message and prints a summary. The new optionsanalyze- bounce- mail --anddry- run --are described in AnalyzeBounceMailCommand.unseen- only - The return code of the log is now the real SMTP code (before it was an internal code, which collided with the codes of
the send queue). The report uses the new columns
bounce_,type bounce_andreason dsn_.status
See Mail Report.
Mail object properties as markers
Similar to the properties of a recipient, the properties of the mail object can be used as markers in the content of
an email. For example, the reply-to address can be printed in the footer with ###MAIL_.
- All properties of the mail object with a getter named
get<Property>can be used. The allowed properties are set by the new extension setting mailFields. - By default these markers are available:
###MAIL_,subject### ###MAIL_,from Email### ###MAIL_,from Name### ###MAIL_,reply To Email### ###MAIL_andreply To Name### ###MAIL_.organisation###
New commands
mail:: Delivers waiting recipients whose retry time is reached.retry- failed mail:: Removes delivered and failed entries after the configured retention time (sentRetentionDays: 30 days, failedRetentionDays: 90 days by default).queue- cleanup mail:: Deletes all queue entries with a given status. Withoutqueue- purge --it only shows how many entries would be deleted.force
See Command Controller.
Update notes
Important
This version adds the database table tx_. After the update, open
Admin Tools > Maintenance > Analyze Database Structure and apply the suggested changes. On the command
line, run vendor/ or, if typo3_console is installed,
vendor/.
Important
The table tx_ gets the columns bounce_, bounce_ and
dsn_. Apply the database changes as described above and run the upgrade wizard
EXT:mail: Set type and reason of returned mails (vendor/).
Without the wizard, returned mails that were stored by an older version are listed as "Reason unknown".
Recommended after the update:
- Set opsNotificationEmail and/or alertWebhookUrl in the extension settings.
- Add
mail:as a daily scheduler task.queue- cleanup - Make sure the sending is done by the scheduler (
mail:). The manual delivery in the queue module is switched off by default now.mass- mailing - Enable enableEmailCorrection, if editors should be able to correct the email address of failed deliveries. It is disabled by default.
If a mail is deleted in the Queue or Reports module, its queue entries are deleted as well. Queue entries of a mail that was deleted another way are removed with the next send run, without a failure message.
For developers
- New event
MEDIAESSENZ\, see RecipientEmailCorrectedEvent. The constructor ofMail\ Events\ Recipient Email Corrected Event Sendgot the event dispatcher as an additional argument. The class is internal.Queue Service MEDIAESSENZ\sends a message and lets transport errors through. The existingMail\ Mail\ Mail Message:: send Or Fail () sendkeeps its behavior and still returns() falseon errors.MEDIAESSENZ\returns the sent format (Mail\ Service\ Mailer Service:: resend To Recipient () MEDIAESSENZ\) instead of nothing. It is used by the retry and not meant to be called by other extensions.Mail\ Type\ Bitmask\ Send Format - New event
MEDIAESSENZ\, see RecipientBouncedEvent. The values in the data of the DeactivateRecipientsEvent underMail\ Events\ Recipient Bounced Event returnare the values ofCodes MEDIAESSENZ\now.Mail\ Type\ Enumeration\ Bounce Reason - The internal class
MEDIAESSENZ\is removed, the analysis is done byMail\ Utility\ Bounce Mail Utility MEDIAESSENZ\. The enumerationMail\ Bounce\ Bounce Analyzer Returnis deprecated, it was not used for real codes.Codes Logis replaced byRepository:: find Return Codes By Mail () find.Bounce Stats By Mail () - The new classes
Send,Queue Service Alert,Service Sendand the repositories for the queue are internal. Their signatures may change.Queue Lock - The extension now has unit and functional tests for the send queue (
composer test:,unit composer test:).functional