8000 [Mailer] Add a way to retrieve the SentMessage object · Issue #35670 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Mailer] Add a way to retrieve the SentMessage object #35670

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mathieu-bourlet opened this issue Feb 11, 2020 · 7 comments
Closed

[Mailer] Add a way to retrieve the SentMessage object #35670

mathieu-bourlet opened this issue Feb 11, 2020 · 7 comments

Comments

@mathieu-bourlet
Copy link
mathieu-bourlet commented Feb 11, 2020

Description

With this PR: #33967
The messageId provided by the providers is stored in the SentMessage object that is returned by the TransportInterface
I can't find a way to get it (the SentMessage) using directly the MailerInterface as:

  • It is not returned (obviously, it can't because the mail can be sent async)
  • I can't find an event that is launched when the mail is actually sent with the SentObject as a parameter (maybe I am missing something?)

Is it possible to add an Event that is sent with a way to retrieve the final messageId?

Some providers use this messageId to deliver statistics information about the mails (It has soft/hard bounced? The mail is opened? / ...) so I want to be able to store it somehow

If there is no way to get it actually, I could try to provide a PR to add this feature.

@AlexHowansky
Copy link

I just encountered this same issue. The docs here clearly show the top-level send() method directly returning an instance of SentMessage, but the actual code doesn't do that, it just throws the transport's result away. Perhaps Symfony\Component\Mailer\Mailer::send() should be changed from this:

public function send(RawMessage $message, Envelope $envelope = null): void
    if (null === $this->bus) {
        $this->transport->send($message, $envelope);

        return;
    }

To this:

public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage
    if (null === $this->bus) {
        return $this->transport->send($message, $envelope);
    }
}

@mathieu-bourlet
Copy link
Author

I don't think it is the right way to do it because it will only handle the case when the mail is not sent async.

I think an event throw by the Symfony\Component\Mailer\Transport\AbstractTransport just after the $this->doSend($message); (https://github.com/symfony/mailer/blob/master/Transport/AbstractTransport.php#L72) call is a more stable solution.

@AlexHowansky
Copy link
AlexHowansky commented Feb 11, 2020

Yeah, I get that it would be different for async/sync, but the feature is documented. So, which is wrong, the code or the docs? shrug Maybe implement both methods?

@fabpot
Copy link
Member
fabpot commented Apr 13, 2020

As of #36424 (5.1), you can now get the sent message when it was handled by messenger.

@fabpot fabpot closed this as completed Apr 13, 2020
@altcom-neil
Copy link

Hi, could anyone explain how #36424 allows us to get the returned MessageId when sending an email following the instructions here - https://symfony.com/doc/current/mailer.html, I don't see how this relates to MessageHandler?
This is my first foray into Symfony so I don't understand how 'add return statement for MessageHandler' means I can then get the Mesage Id from the SentMessage object that is never returned by the Mailer class?
We are using Mailgun so we must have the message id from Mailgun so we can track delivery of the email. I have been googling every thing I can think of and stepping through code for hours trying to work out how to retreive the SentMessage object with no success. I have in the end simply forked the Mailer class with my own version that doesn't throw away the SentMessage being returned by the MailgunAPI Transport similarly to the code in #35670 (comment) so I can continue further development work but don't want to be using the fork in the live environment.

@reubenporterjisc
Copy link
reubenporterjisc commented Sep 4, 2020

@altcom-neil Did you ever find a solution to your issue? I ended up using the Symfony\Component\Mailer\Transport\TransportInterface as this returns the SentMessage object. The downside is that you cannot send your mails async.

Is there a way to get the SentMessage object using async @fabpot?

@altcom-neil
Copy link
altcom-neil commented Sep 4, 2020

@reubenporterjisc no we were working through the proof of concept so it was more important to get past this stage than spend any more time so I added a custom version of the Mailer class that saves the SentMessage response to a class var and then adds a method to retrive it:

`
class CustomMailer implements MailerInterface
{
private $transport;
private $bus;
private $dispatcher;

private $sentMessage; // new variable to store the result of sending message through the $transport so that we can get the MessageId returned by the API

public function __construct(TransportInterface $transport, MessageBusInterface $bus = null, EventDispatcherInterface $dispatcher = null)
{
    $this->transport = $transport;
    $this->bus = $bus;
    $this->dispatcher = class_exists(Event::class) ? LegacyEventDispatcherProxy::decorate($dispatcher) : $dispatcher;
}

public function send(RawMessage $message, Envelope $envelope = null): void
{
    if (null === $this->bus) {
        $this->sentMessage = $this->transport->send($message, $envelope); // store result in sentMessage var
        
        return;
    }

    if (null !== $this->dispatcher) {
        $clonedMessage = clone $message;
        $clonedEnvelope = null !== $envelope ? clone $envelope : Envelope::create($clonedMessage);
        $event = new MessageEvent($clonedMessage, $clonedEnvelope, (string) $this->transport, true);
        $this->dispatcher->dispatch($event);
    }

    $this->bus->dispatch(new SendEmailMessage($message, $envelope));
}

/**
 * Returns the SentMessage object returned by sending the email through the transport.
 * Gives access to the MessageId returned by the API used to send the Email
 * @return Symfony\Component\Mailer\SentMessage
 */
public function getSentMessage() {
    return $this->sentMessage;
}

}
`

No idea what to do about the rest of the code and how to get to the MessageId if $this->bus is not null but when doing the basic sending using

$mailer->send($email);
from - https://symfony.com/doc/current/mailer.html#handling-sending-failures
then on success I can retrieve the sent message and then message id allowing me to handle the callbacks from Mailgun telling us whether or not the email has been delivered.

$sentMessage = $mailer->getSentMessage(); $messageId = $sentMessage->getMessageId();

p.s. no idea how to get the code formatter to work on here properly either but you can get the jist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants
0