unit testing Mail::send() - php

Say I'm sending an email with \Illuminate\Support\Facades\Mail::send(). How would I test this to see if an email had in fact been sent?
https://laravel.com/docs/5.8/mocking#mail-fake mentions Mail::assertSent() but that requires you a pass to it a #param string $mailable variable and idk what that variable would need to be with Mail::send().
Any ideas?

It looks like you need to call Mail::fake() while testing, and Mail::send() when in production. That should be part of your testing facade.
Even if you your code claims the mail was sent, you'll may want to go a step further and verify the mail was actually received. This will require access to the destination mail server (hard!) ... or you could use something more public like Dispostable.

Related

Can't send mail with Lumen framework and no error appears

Since yesterday I have had problems sending emails with Lumen. I think I have followed all the steps in the documentation correctly, but unfortunately I cannot send anything. Moreover, no error is displayed (I have activated APP_DEBUG=true), and I am sure that the credentials of the smtp server are correct. I also did composer require illuminate/mail.
Here are my modifications in bootstrap/app.php (I have $app->withFacades(); uncommented).
Here is my build function content: return $this->view('emails.mailTemplate', ['message' => $this->message]);.
And the line of code that ask to send mail: Mail::to("wewanthalflifethree#gmail.com")->send(new sendMail($destEmail, $subject, $message));.
Did I do something wrong? :/
Thx in advance for help!
EDIT: I just noticed something, the code stop working when I send the mail. If I add an echo after Mail::send, it will be appear on the page.
I have a problem with the Exceptions handler. By following this answer (which consists in adding a dd in the render function of Handler.php), I am now able to see what's going wrong.
So, here is the reason why my mail didn't send and why my page turned blank: Object of class Illuminate\Mail\Message could not be converted to string (View: /home/serveur-web/api.sl-projects.com/resources/views/emails/mailTemplate.blade.php).
The problem came from the fact that I was using the variable name $message, and this causes problems because it seems to be used in the class that handles the mails. My problem was therefore solved by renaming this variable $mailContent.
I hope this will help other people. :D

Is there a way to get the body of a Laravel Mail object to store in a variable?

I'm using the Laravel Mail API to generate mailables and send them out.
Everything is working fine with that.
However, I also want to log the email bodies in the DB.
In order to do that though, I need to first get the bodies of the emails I'm sending out.
In the Laravel docs, they have a snippet about how to output an email to the browser here:
https://laravel.com/docs/5.7/mail#previewing-mailables-in-the-browser
However, I don't want to output the email to the browser. I want to store it in a variable.
Is that possible? If so, how? Thanks.
Like the docs suggested, I tried something like the following:
$body = new App\Mail\InvoicePaid($invoice);
However, I got an error saying that I have to actually return the new Mail object in order for it to work (i.e., do what they do in the example code in the docs).
Previous paragraph tells you how to capture the rendered template:
$html = (new App\Mail\InvoicePaid($invoice))->render();
echo $html;

Laravel 5.3 send Mail to multiple email-adresses

I'm using Laravel 5.3 and trying to send a newsletter Mail to specific mail adresses.
Currently I do the following:
$newsletterMailAdresses = Newsletter::where('user_id', $userID)->pluck('mailAdress');
This returns an array of email-adresses, to which the emails shouuld be sent.
What I then (normally) use to send mails is:
Mail::to("someMailAdress")->send(new newsletterMail($newsletterText));
I thought about just passing that array into the to function but I'm quite sure it won't work.... What you propably could do, is a foreach with every mail adress and send the mails, but is this the way how this should be done or is there a better way?
PS: I know that thread but its about Laravel 4, so there are many things changed.
I think it should work, when you pass an array. Check the reference:
https://laravel.com/api/5.3/Illuminate/Mail/Message.html#method_to
The first parameter can be an array. Try it.
Mail::to(['array','of','emails'])...
also
Mail::cc(['array','of','emails'])...
and
Mail::bcc(['array','of','emails'])...
I think it should work, but you can also try to do like this:
Mail::raw('No Body', function($message) use ($emails)
{
foreach ($emails as $email)
{
$message->to($email);
}
});
I use like this in my application and it works fine!
Maybe you can also try to send one email and vereify it works fine, then you can try sending the email using the array of emails.
From the Laravel 5.4 documentation on Sending Mail:
The to method accepts an email address, a user instance, or a collection of users. If you pass an object or collection of objects, the mailer will automatically use their email and name properties when setting the email recipients, so make sure these attributes are available on your objects.

fullBaseUrl not correctly used for images when sending mails via console

We recently switched our mail implementation to be console-based.
Unfortunately, the following Helper-code within an e-mail view is now broken:
$this->Html->image('file.png', array('fullBase' => true)
Although we set CakeEmail's domain var to the correct value:
$email->domain('www.domain.tld');
The helper produces the following
http://home/www/domain.tld/htdocs/img/file.png?1382530379
Current behavior:
The asset timestamping of the file just works like a charme, but the fullBase is unfortunately, I think due to the console call, the UNIX-path of the file.
Expected behavior:
The fullBaseUrl should be the domain, which we're setting in the CakeEmail object.
Folks: Is there any other possibility, besides putting the domain on my own to the $this->Html->image() call?
CakeEmail::domain doesn't do what you want
The domain function is not there for configuring the base url in assets, it's purpose is to serve as the host name for the message id. A quick look at the code, and checking where $this->_domain is used should confirm that it's only use is related to message headers.
fullBaseUrl
The option to set is App.fullBaseUrl either by calling Router::fullBaseUrl:
// inside email-sending command, before sending an email
Router::fullBaseUrl('http://example.com');
Or by configuring it directly in core.php:
// anywhere before an email is sent
Configure::write('App.fullBaseUrl', 'http://example.com');

Spam check before sending using Zend_Mail

I'm using Zend_Mail and the following code to send my email messages.
$mail = new Zend_Mail('UTF-8');
$mail ->setBodyText($plainBody)
->setBodyHtml($htmlBody)
->setSubject($subject)
->setFrom(FROM_ADDR, FROM_NAME)
->addTo($email, $name )
->addHeader(MY_HEADER, serialize( array( 'foo' => 'bar' ) ) )
;
I need to check the spam rating for the prepared message and I'd like to do it using SpamAssassin.
I thought to create a file with the contents and running something such as exec('spamc $filename'), but how to get the file content with the full MIME body?
I noticed that there's a _buildBody() function in Zend_Mail_Abstract class (library/Zend/Mail/Transport/Abstract.php) that's return that, but that's a protected function.
Thanks
If you want to use SpamAssasin, then run your email message through spamc:
http://spamassassin.apache.org/full/3.1.x/doc/spamc.html
Spamc is the client half of the spamc/spamd pair. It should be used in
place of spamassassin in scripts to process mail. It will read the
mail from STDIN, and spool it to its connection to spamd, then read
the result back and print it to STDOUT. Spamc has extremely low
overhead in loading, so it should be much faster to load than the
whole spamassassin program.
You can do use in PHP by:
Writing the message into a temporary file and running shell_exec('spamc < message.tmp'), or
Running the command with proc_open() then send message via STDIN.
I am assuming you want to simulate a spam check on the recipient's end. That's an interesting idea, but note that the results it will give you will be far from 100% realistic. After all, it's the sending process that adds much of the vital information that helps determine whether an E-Mail is spam (e.g. the sender IP and routes.)
Anyway, to do this, you will probably have to implement a custom Zend_Mail_Transport class, based on the example of Zend_Mail_Transport_Smtp. Any data that transport class sends to the SMTP server, you would have to re-route to a text file. As far as I can see at a cursory glance, it's going to be a bit of work but not impossible.

Categories