Is there a way to get the message-id of the to be send email within Laravel Mailables?
I currently get the id like this which just works fine, but since this doesn't support markdowns and stuff, I would prefer to get around this:
Mail::send('mail.contact.confirmation', $contactData, function (Message $message) use ($mailTo, $subject, &$headers)
{
$headers['message-id'] = $message->getSwiftMessage()->getId();
$message->to($mailTo)->subject($subject);
});
Thanks for any advice.
I just had to figure this out on my own, so take my answer with a grain of salt (although it works for me).
Within the "build()" function of a Laravel Mailable, you can do:
$this->withSwiftMessage(function ($swiftmessage) {
echo $swiftmessage->getId();
});
Hopefully that gets you started. My use-case was editting the ID, so I used:
$this->withSwiftMessage(function ($swiftmessage) use ($newId) {
$swiftmessage->setId($newId);
return $swiftmessage;
});
I had the same challenge where I had to run a Laravel Queue where message ID should be displayed after sending an email. I solved this issue like this.
namespace App\Jobs
inside handle()
$message_Id="";
Mail::send('emails.thanks',array(),function($message) use(&$message_Id){
$message_Id=$message->getId();
$message->to('enter email id','any name')->subject('Please check the message ID');
});
echo $message_id;
Related
I want to fetch all emails in inbox and store them in realtime but the way i m doing it is a little bit wrong :
it's something like this:
class Kernel extends ConsoleKernel
...
$schedule->call(function () {
// connect using credentials
//get all emails
//copy emails
//delete emails when they get copied correctly
})->everyMinute(); // repeat
this Guarantees that the emails in the database will not be copied because the emails are no longer in the inbox .
But now we have a case where we need to keep these messages so we replaced this with :
// connect using credentials
//get all emails
//filter only unseen
//copy emails
//mark these emails as seen
But the problem of all of these solution is that we get emails .
The solution we did is working but added another problem of reloading same emails over and over .
I reread the Documentation and found this
possible solution :
Using events that triggers in the entire package and capture the new event witch gets triggered when a new email is received.
In this example i found some useful methods and classes .
class CustomMessageNewEvent extends Webklex\PHPIMAP\Events\MessageNewEvent {
/**
* Create a new event instance.
* #var \Webklex\PHPIMAP\Message[] $messages
* #return void
*/
public function __construct($messages) {
$this->message = $messages[0];
echo "New message: ".$this->message->subject."\n";
}
}
But i m not sure how to implement them in Laravel , juste where and how should i register / capture this `new` Event !
**Especially that we have multiple Client instances not only one ( foreach user ... )**
Thank you so much for reading all this and hopefully people find this question useful.
When I've done similar tasks in the past I've used the Message-ID defined in the email spec to identify each email uniquely.
You can use your IMAP library to get a list of emails with their Message-IDs, then compare those Message-IDs to your database. Just make sure you add a new field to your Email model (or whatever you've called it) to store the Message-ID.
I want to get the render of an email before to send it.
I created a TemplatedEmail with htmlTemplate and context, it works fine for sending but how get the generated template with context to save it in database ? (customer needs)
I tried the getBody() but seems to work only with text template as I get A message must have a text or an HTML part or attachments.
$email = new TemplatedEmail();
$email->htmlTemplate($htmlTemplate);
$email->from($from)->to(...$to)->subject($subject);
$email->context($context);
dd($email->getBody());
I thought to use the render method but I'm in a service and not sure if it's a good way to store in database.
Symfony only renders the message when actually sending it, via an Event Listener. The class responsible from doing the rendering is BodyRenderer, from the Twig Bridge.
But nothing stops you from rendering the message yourself.
You have the template and the context variables, so you could simply inject Twig wherever you are doing the sending, render the template to a string and do whatever you need with that.
You could also register your own MessageEvent::class listener, set it with lower priority than the one registered by the Twig Bundle (it uses the default priority) so it's executed after that one, and then you could access the message body since it would have been rendered already. This is (very) slightly more complex, but you'd gain some performance since you wouldn't be rendering the template twice.
Which approach to use would depend on your application, your constraints, etc. But the important bit is to realize on what part of the process you'll find the body actually rendered, or render it yourself if you want it before that.
For future information it's possible to render the template in a service using the documentation here https://symfony.com/doc/current/templates.html#rendering-a-template-in-services
Here is solution (for logging templated email to DB, but can be easily customized to anything else) using EventListener
use App\Entity\EmailLog;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Mailer\Event\MessageEvent;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
#[AsEventListener(event: MessageEvent::class, method: 'onEmailSent', priority: -1)]
class EmailLogListener
{
public function __construct(
private EntityManagerInterface $entityManager
) {}
public function onEmailSent(MessageEvent $event): void
{
$message = $event->getMessage();
if (!$message instanceof Email) {
return;
}
$log = new EmailLog();
$log
->setSentFrom(array_map(function (Address $address) {
return $address->getAddress();
}, $message->getFrom()))
->setSentTo(array_map(function (Address $address) {
return $address->getAddress();
}, $message->getTo()))
->setSubject($message->getSubject())
->setText($message->getHtmlBody());
$this->entityManager->persist($log);
$this->entityManager->flush();
}
}
I've been having this issue where I want to send a plaintext email to a user (me in this case) but the email adress is inside of an object I retrieved from the database. All examples using Mail::raw use a string but not a passed variable. Is there a way to do that?
Code:
Mail::raw($messageContent, function($message)
{
$message->to($foo->email);
});
This is what I want, in essence. $foo is a variable declared in the function that this is in. I don't want to make $foo a class variable because I am only using it here.
Thanks for helping!
Mail::raw($suggestionString, function($message) use ($follower)
{
$message->to('support#company.com')->subject('Suggestion')->replyTo($follower->email);
});
When you reply to this message it's automatically sent to the email specified in ->replyTo()
I'm trying to use database driver for queuing emails. Using Mail::send emails are sent as expected. But when I use Mail::queue the user object passed to the view gets null "Trying to get property of non-object".
I have a mailer class and these are the methods responsible for sending the email:
public function sendAssignmentEmail(User $user)
{
$this->to=$user->email;
$this->view='emails.assigned';
$this->data=compact('user');
$this->subject='subject';
$this->deliver();
}
public function deliver()
{
$to=$this->to;
$subject=$this->subject;
$from=$this->from;
return $this->mailer->queue($this->view,$this->data, function($message)
use($to, $subject, $from)
{
$message->from($from, 'example.com');
$message->to($to);
$message->subject($subject);
});
}
What am I doing wrong?
I know that the problem is with the
$this->data
If I pass an array the queue will work, but if the data is in form of an object it won't.
Mail::queue is essentially exactly the same as Mail::send except your queuing them to be sent.
As a result it expects the same parameters as Mail::send in which the second argument needs to be an array, hence why it works when you supply an array and doesn't when you supply an object.
Simply change $this->data=compact('user'); to be in the form of an array and it'll work fine for you.
The docs are super useful when you get stuck on things like this :).
I'm a bit of a noob with Laravel but I'm setting up a bug tracking system and have a question about how to remove multiple instances of sending mails. Let me show you how I've got it set up currently:
public function store(UsersRequest $request)
{
$user = User::create($request->all());
Mail::queue('emails.master', ['user' => $user], function($message) use ($user) {
$message->to('someone#somewhere.com')
->subject('New User Created');
});
return redirect('/users');
}
So I have this method in a controller which creates a new user in my system, then I send the mail out. What I'd like to do is strip the mail call out to one line of code.
What's the best way to achieve this?
What I've found so far, is setting up a service to handle this - like this: http://lukefair.com/create-a-mailer-service-with-laravel-and-a-basic-working-example-of-dependency-injection/
This seems like a good idea to my noob brain and would achieve what I need it to. Is there a better way to do this than creating a service? Making use of events perhaps (although, I guess I'd still need a service for that)?
As I said, I'm a bit of a Laravel noob and haven't got these patterns and ways of doing things down yet.
Any advice would be great. Thanks!
The typical solution for problems like this is, in the Laravel world at least, to create a service provider. The article you linked is a good fit for what you are looking to do.
If you want to be able to access your new mailer class globally as you can with Mail and Request and any of the other familiar Laravel facades, you can create your own and it will be usable from anywhere in your application.