symfony: [Mailer] Sending Messages Async with json serializer does not work
Symfony version(s) affected: symfony/mailer: 4.3.4
Description
Sending Messages Async with json serializer does not work with SendEmailMessage.
Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException : Cannot create an instance of Symfony\Component\Mime\RawMessage from serialized data because its constructor requires parameter "message" to be present.
/home/vagrant/www/fxbackoffice.local/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php:505
...
How to reproduce
framework:
messenger:
serializer:
default_serializer: messenger.transport.symfony_serializer
symfony_serializer:
format: json
transports:
async: "%env(MESSENGER_TRANSPORT_DSN)%"
routing:
'Symfony\Component\Mailer\Messenger\SendEmailMessage': async
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 18
- Comments: 35 (21 by maintainers)
Commits related to this issue
- bug #38433 [Mime] Fix serialization of RawMessage (gilbertsoft) This PR was squashed before being merged into the 4.4 branch. Discussion ---------- [Mime] Fix serialization of RawMessage | Q ... — committed to symfony/symfony by fabpot 4 years ago
- Stop using JSON format for messenger as there is a bug in Symfony (see https://github.com/symfony/symfony/issues/33394). Using the combination of JSON and native PHP serialization is not a way as it c... — committed to fedys/mautic by fedys 10 months ago
- Stop using JSON format for messenger as there is a bug in Symfony (see https://github.com/symfony/symfony/issues/33394). Using the combination of JSON and native PHP serialization is not a way as it c... — committed to mautic/core-lib by fedys 10 months ago
@Nyholm Personally I am not so sure this is Serializer’s issue. It looks to me like architectural mistake in Mailer/Mime component - there is
SendEmailMessagemessage and even its name states it’s sendingEmail, notRawMessagewhich is used in signature. Not to mentionRawMessage→Messageinheritance which is weird (totally dropped parent class attributes, not called parent constructor).RawMessageseems to be unnatural abstraction layer to me. Code like this confirms my assumptions:It’s from
Symfony\Component\Mailer\Envelope, but there are other places with similar workarounds.RawMessageis mainly used for types in signatures while actual usage requires its child classes. Unfortunately it’s widely adopted and probably impossible to change at this point.IMO Mailer/Notifier (and every other component that works with emails) should work with actual
Emailmessages because it’s impossible to callSymfony\Component\Mailer\Mailer::send()withRawMessage(well, at least without exlipicEnvelopewhich is not DX-friendly) - it will end up withLogicExceptionregardless of how it’s handled internally by Mailer:Without bus (using
TransportInterface):Event dispatcher:
Messenger bus:
Changing
Mailer::send()andSendEmailMessagesignatures and usingEmailwould solve this issue and IMO would be generally better since it wouldn’t allow developers to get into thatLogicException. For now, according to BC-promise,Mailer::send()could simply check if$messageis an instance ofEmailand if not then it should check if$envelopeis passed - if not, it could throw exception at this point, without calling transport/dispatcher/bus. It could also trigger deprecation warning and signature could be changed in the next major version. IfMailer::send()can’t createEmailinstance fromRawMessageandEnvelope, there probably should beDenormalizerInterfaceimplementation forSendEmailMessageobject so proper email message would be deserialized.But it’s Symfony’s team decision of course 🙂 Maybe it was done this way for a reason I just don’t get.
The issue still exists. I had to use the NativePhpSerializer to make it work.
serializer: messenger.transport.native_php_serializerI did an ugly trick with serializer, because SendEmailMessage structure is too complicated for json. The special serializer was added to a project
And one more, I did not find how to inject context to serializer for specific class, so there is a file for exclude attributes:
Firstly I added a specific route and serializer, but there is an error when SendEmailMessage goes to failed queue it decoded as json and this task never be processed successfully.
@fabpot please, could you explain why is it designed this way ( https://github.com/symfony/symfony/issues/33394#issuecomment-791295930 ) ? 🙏 as you are the author of these classes/logic. understanding it will be a good start to wrap around this issue. notably
RawMessage -> Message -> EmailRawMessageseems to me that
RawMessageis kinda substitute for an interface.not actually solved by the related PR, as it was fixing only the case of
serialize($rawMessage)