Laravel + Swift Mailer: Error: no valid recipients - php

Note: this sadly is no duplicate, I already tried everything mentioned there.
I tried to set up a connection to my mailserver with Laravel/Swiftmailer. The Mailing section of my .env looks as follows:
MAIL_DRIVER=smtp
MAIL_HOST=<THE MAILHOST>
MAIL_PORT=465
MAIL_USERNAME=<THE USERNAME>
MAIL_PASSWORD=<THE PASSWORD>
MAIL_ENCRYPTION=ssl
Personal information is censored for obvious reasons, but the configuration does work. I tested it by connecting to the server with this configuration with thunderbird and it works like a charm.
Here is where I call the Mailable:
public function from_id(string $id): User
{
.
.
.
Mail::to(<WORKING EMAIL ADRESS>)->send(new OrderShipped());
}
Thats how the Mailable looks like (it basically is the example one from the laravel docs):
public function build()
{
return $this->view('email_templates.simple_test');
}
I debugged into the code and there are actually two exceptions thrown, altough whoops! only shows the latter:
Expected response code 250/251/252 but got code "554", with message
"554 5.7.1 : Recipient address rejected: Access
denied"
Expected response code 354 but got code "554", with message "554 5.5.1
Error: no valid recipients"
I tried to sent an email from the perfectly working mailserver via thunderbird to the <WORKING EMAIL ADRESS> and the mail got sent and received in a fraction of a second and without any problems/errors. Basically, I tried to reproduce the exact same scenario with a different tool. So from my point of view, the error must be in the codebase.
Thanks in advance

This seems to be a SMTP error, what kind of error code you are getting ?
Code 354: means the SMTP server telling Laravel to proceed and send the body of the email. Note that this is what is expected, and not what you received.
Code 554: from a SMTP server indicates: "Transaction Failed", and you'll note that this is what you actually got.
The reason this is failing is indicated further in the message: "Error: no valid recipients."
Without further data it will be hard to tell why the recipient isn't set properly on your codebase.
For complete list of smtp erro codes can visit: https://sendgrid.com/blog/smtp-server-response-codes-explained/

You need to contact your sysadmin to ask if you need STARTTLS or just TLS.
STARTTLS starts a plain connection and then switches to a secure TLS 'channel', TLS connects to secure connection directly but is less compatible.
if the answer is STARTTLS use the port 587
else keep your port but verify it with your sysadmin
another reason could be that you account was banned or your IP blocked

My answer isn't Laravel specific, as I'm working in Yii2 environment, but the error message was the same as above. (Maybe I'll help someone someday.)
My original problem: the contact form was not working while at other places the app was sending out automatic mails properly - which was weird.
It turned out that when setting the 'from address' in the SwiftMailer config I put in the contacting person's (sender's) e-mail address, which was not allowed.
When I configured the proper user account (which I use to authenticate to the SMTP server) as the sender address, there was no issue. As soon as I tried to 'mimic' that the users are sending the e-mails from their own addresses, I was given that same message.
All I could do to "fix" this is to include the 'ReplyTo' parameter with the e-mail, this way when I reply to the incoming mail in Outlook, the actual sender's address is populated instead of the SMTP mailbox used for contact-mail-sending.
I've also included a short message at the bottom of the Body to indicate who the sender is (name and address) - just for convenience.

Your setup looks a little strange to me. Please try with the below syntax (note here I've included a $_orderObject variable as a placeholder to represent order details):
app/Mail/OrderShipped.php
<?php
namespace App\Mail;
use Illuminate\Mail\Mailable;
class OrderShipped extends Mailable
{
protected $_name;
protected $_orderObject;
public function __construct($name, $order)
{
$this->_name = $name;
$this->_orderObject = $order
}
public function build ()
{
return $this->to (<CONFIRMED WORKING EMAIL>)
->subject ('New Order!')
->view ('email_templates.simple_test')
->with ([
'name' => $this->_name,
'order' => $this->_orderObject
]);
}
}
//calling it
public function from_id(string $id): User
{
$name = << $this->getUserNameById ($id) >> // fake method
$orderObject = << $this->getLatestOrderByUserId($id) >> // fake method
Mail::send(new OrderShipped($name, $orderObject));
}

Related

How can I get a list of errors from phpmailer?

I'm sending emails through PHPMailer and I found a specific case when the email address is a non-existing email address that belongs to the sending gateway
[ e.g - gateway email: 1234#1234.com and the email address 0000#1234.com], phpmailer returns the following error: "Recipient address rejected user unknown in virtual mailbox table".
It would be great if a status code might be present there (I want to know if is a hard bounce or a soft bounce) and also, I want to know what kind of other specific cases might occur.
SMTP errors are covered by RFC5321 and related RFCs, and you can see most significant errors codes there. When you get an SMTP error in PHPMailer, the SMTP error code is put in the $error property of the SMTP instance, which is protected, but you can fetch it using getError(). From normal PHP code this would be done with:
$error = $mail->getSMTPInstance()->getError();
The result is an array like this:
[
'error' => $message,
'detail' => $detail,
'smtp_code' => $smtp_code,
'smtp_code_ex' => $smtp_code_ex,
]
The thing that will be of most interest to you is the smtp_code element.
Note that this only applies when you're sending via SMTP; if you're sending via mail(), this won't be populated.

How do we solve error 554 5.5.1 (no valid recipients) when using PHP Swiftmailer?

When testing out our mail server we stumbled accross an error that prevents us from sending mails via PHP, though regular sending/receiving per Mail-in-a-box works without any problems.
We are running a separate Ubuntu 18.04 server that only has Mail-in-a-box with all its needed components running.
Output in the error.log text file
PHP Fatal error: Uncaught Swift_TransportException: Expected response
code 354 but got code "554", with message "554 5.5.1 Error: no valid
recipients\r\n"
PHP file
$request_email = $_POST['request-email'];
$request_name = $_POST['request-name'];
$request_text = $_POST['request-text'];
$transport = (new Swift_SmtpTransport('data.abc.xy', 587, 'tls'))
->setUsername('contact#abc.xy')
->setPassword('*******')
->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false)));
$mailer = (new Swift_Mailer($transport));
$message = (new Swift_Message('Name: '. $request_name))
->setFrom(['' . $request_email => '' . $request_name])
->setTo(['contact#abc.xy'])
->setBody('E-Mail: ' . $request_email . $request_text)
->setContentType("text/html");
$result = $mailer->send($message);
What we have tried is to reinstall all of Mail-in-a-box and all of the components and checking everything for spelling mistakes. The ricipient does exist on our mail server and can receive and send mails manually via the client.
I have solved this error (554) just adding to laravel (.env file) these 2 lines:
MAIL_FROM_ADDRESS=you#email.com
MAIL_FROM_NAME="you#email.com"
Finally, run this command to flush mail cache config:
php artisan config:cache
The 554 5.5.1 error is the SMTP error "no valid recipients". It can occur if you've misspelled the recipient addresses but it can also occur if you are not properly authenticating to the outgoing server.
So the problem is that abc.xy is not a registered domain so you can't send an email to this address. I think it's not something related to your code.
You can catch the Swift_TransportException error and handle it in your own codebase like :
try {
$result = $mailer->send($message);
}
catch (Swift_TransportException $e) {
echo $e->getMessage();
}
I had the same problem in Laravel and fixed it by changing "from" to "replyTo".
I believe the problem is when sender's and app server's domains differs.
// in Laravel
// ...
namespace App\Notifications;
// ...
public function __construct(User $from, string $body)
{
$this->from = $from;
$this->body = $body;
}
// ...
public function toMail($notifiable)
{
$message = new MailMessage;
$message->subject('some subject');
// "no valid recipients" error:
// $message->from($this->from->email, $this->from->name_full);
// works:
// sender globally set in .env (MAIL_FROM_NAME, MAIL_FROM_ADDRESS)
$message->replyTo($this->from->email, $this->from->name_full);
$message->line(new HtmlString(nl2br($this->body)));
return $message;
}
// Swiftmailer respectively
// ...
$message = (new Swift_Message('Name: '. $request_name))
->setFrom(['contact#abc.xy' => 'contact'])
->setReplyTo([$request_email => $request_name])
// ...
I solved this issue by ensuring that the email address set in env file
MAIL_USERNAME=example#example.com
is the same as the "from" address in my custom notification mail class' toMail function
->from('example#example.com','My app name')
It seems as though some email services find it odd that the app is sending an email using one credential (env credentials) but a different email address is being masked as the sender.
A better solution would probably be to never set a "from" address in your notification classes.
One more thing is that it might be everything OK with your code, but the receiver address simply doesn't exist. We have a lot of customers from other companies and with time people simply change their job and the email address they used is deleted
"receiver email address doesn't exist anymore"
so if you try to send an email to non existing email address you will get that same error.
In my case, I got this error because I had forgotten to set the MX record on the recipient's domain, so the app didn't know where to deliver the email.
Another reason can be the domain being blacklisted, check spamhaus

Add mail to Send folder with SwiftMailer

I'm using SwiftMailer for PHP from swiftmailer.org
Everything works well but I wonder if there is a way to add the sent message into the sent folder from the mail account that SwiftMailer is sending from?
That's all, have a nice day.
According to the developer, swiftmailer cannot copy to Sent folder because it is a mail sender and not mailbox manager.
As mentioned on the github page:
Swiftmailer is a library to send emails, not to manage mailboxes. So, this is indeed out of the scope of Swiftmailer.
However, someone from php.net posted a solution that might work for you:
Use SwiftMailer to send the message via PHP.
$message = Swift_Message::newInstance("Subject goes here");
// (then add from, to, body, attachments etc)
$result = $mailer->send($message);
When you construct the message in step 1) above save it to a variable as follows:
$msg = $message->toString();
// (this creates the full MIME message required for imap_append()!!
// After this you can call imap_append like this:
imap_append($imap_conn,$mail_box,$msg."\r\n","\\Seen");
I've had similar problem and Sutandiono's answer got me into right direction. However because of completeness and as I had additional problem connecting to an Exchange 2007 server, I wanted to provide a complete snippet for storing message to Sent folder on IMAP:
$msg = $message->toString();
// $message is instance of Swift_Message from SwiftMailer
$stream = imap_open("{mail.XXXXX.org/imap/ssl/novalidate-cert}", "username", "password", null, 1, array('DISABLE_AUTHENTICATOR' => 'GSSAPI'));
// connect to IMAP SSL (port 993) without Kerberos and no certificate validation
imap_append($stream,"{mail.XXXXX.org/imap/ssl/novalidate-cert}Sent Items",$msg."\r\n","\\Seen");
// Saves message to Sent folder and marks it as read
imap_close($stream);
// Close connection to the server when you're done
Replace server hostname, username and password with your own information.

Can't send email via SMTP because "550 - Relay Not permitted"

I'm using CakePHP to send automated emails to clients. It's been working great, but it seems some recipients aren't receiving our emails. So I decided to use the SMTP option for sending emails, and route emails through our email provider at Media Temple.
However, when trying to send email from a Media Temple account, I get the error "550- relay not permitted".
That sounds like the Media Temple server is just plain not allowing me to send mail through it.
That's odd because I've confirmed the username and password I'm using is correct and I can send mail via SMTP through it from my macmail client and iPhone mail client. I've also confirmed my cakephp email settings are correct, because I can send emails via SMTP with a gmail account with the exact same configuration in cakephp.
Any idea why I'm getting this error and how to resolve it?
Thanks
Here's the code that handles sending an email. I use this class just like the regular EmailComponent from within many different controllers.
class CanadafindsEmailerComponent extends EmailComponent
{
...
function send($content = null, $template = null, $layout = null) {
if(!in_array(TECHY_MONITOR_EMAIL,$this->bcc) && is_array($this->bcc))
$this->bcc[]=TECHY_MONITOR_EMAIL;
else if (!in_array(TECHY_MONITOR_EMAIL,$this->bcc) && !is_array($this->bcc))
$this->bcc=array(TECHY_MONITOR_EMAIL);
if(DEVSITE){//commented-out code are settings for smtp with gmail, which works fine
$this->delivery = 'smtp';
$this->smtpOptions = array(
'port'=>'465',//'465',
'timeout'=>'30',//'30',
'auth' => true,
'host' => 'ssl://mail.thenumber.biz',//'ssl://smtp.gmail.com',
'username'=>USERNAME,//'USERNAME#gmail.com',
'password'=>SMTP_PASSWORD//,
);
$this->to=$this->correctFormatOn($this->to);
$this->bcc=$this->correctFormatOn($this->bcc);
$this->cc=$this->correctFormatOn($this->cc);
$this->replyTo=$this->correctFormatOn($this->replyTo);
$this->from=$this->correctFormatOn($this->from);
}
return parent::send($content,$template,$layout);
}
function correctFormatOn(&$email){
if(is_array($email)){
$copiedEmail=array();
foreach($email as $singleEmail){
$copiedEmail[]=$this->correctFormatOnSingle($singleEmail);
}
$email=$copiedEmail;
}else{
$email=$this->correctFormatOnSingle($email);
}
return $email;
}
function correctFormatOnSingle(&$email){
$subEmails=explode(",",$email);
$fixedSubEmails=array();
foreach($subEmails as $subEmail){
$fixedSubEmails[]=preg_replace('/<?([^< ]+)#([^>,]+)[>,]?/i', '<$1#$2>', trim($subEmail));
}
$email=implode(",",$fixedSubEmails);
return $email;
}
}
The main problem I was having was that clients weren't receiving emails from our server, (and so I wanted to use an SMTP server to see if that would fix it, instead of the server's default email server).
But I managed to get those clients to receive emails from the server by making some other changes, thus removing the need to use SMTP and the Media Temple email server.
(As an FYI, I found that we were getting bouncebacks from client email servers stating Diagnostic-Code: smtp; 550 Access denied - Invalid HELO name (See RFC2821
4.1.1.1), but they were being sent directly back to the server, and going into the linux user account "www-data". (I read them in /var/mail/www-data, just using tail and vim). I found that postfix, which was handling the sending of emails, was marking the email sender's hostname (ie, "HELO name") as canadafinds3, the name I gave the server in Rackspace, not the domain name: canadafinds.com. So I changed that in /etc/postfix/main.cf, restarted postfix, et voila! No more bouncebacks from those particular clients, and everyone's happy again.)
I ended up writing my own PHP mail() script based on https://web.archive.org/web/20180401094709/http://www.dreamincode.net/forums/topic/36108-send-emails-using-php-smtp-direct/ in order to circumvent this error.

Why is email not being sent through PHP even though it is being reported as sent?

I'm trying to sends mails in PHP. The code I used for sending a mail in CakePHP is given below. I get the message 'Simple Email Sent' in my web page but the mail is not delivered to my inbox. Am I missing something?
The values in the to, subject and link fields are set with the values entered in the user interface.
$this->set('to',$this->params['form']['to']);
$this->set('subject',$this->params['form']['subject']);
$this->set('link',$this->params['form']['link']);
$this->Email->to = to;
$this->Email->subject = subject;
$this->Email->from = 'someperson#somedomain.com';
$this->Email->delivery= 'mail';
$this->Email->sendAs='text';
$this->Email->template = 'simple_message';
//$this->Email->send(link);
if ( $this->Email->send(link) ) {
$this->Session->setFlash('Simple email sent');
} else {
$this->Session->setFlash('Simple email not sent');
}
On a Linux system, you'll probably have a sendmail script installed already, and PHP will use that. If this is what you have and it's not working, then I'd look for mail configuration problems in your Linux system itself.
On a Windows system, you'll need to configure the SMTP server you want PHP to send mail to. The normal way to do this is in php.ini. The instructions for this are here.
Unless you have set Email->delivery this should be the same for CakePHP - it should default to whatever PHP uses.
Note: If you are using your own Linux install, it could just be that your ISP is blocking port 25, which your mail server is using. In that case you'll need to configure linux to route email to your ISP's email server. Maybe this will help?
Since when is 'to' (line 4) a valid destination email address?
You need to use variable syntax for setting to 'to' line, and the 'subject' line. Those lines should read
$this->Email->to = to;
$this->Email->subject = subject;
Also, I believe there is an attribute in the Email component called error (I cannot find it in the documentation currently) that will help you debug. This may not be totally correct; I use the Email component with SMTP, and there is an attribute that gets set by the Email component called smtpError. I believe there is one called error that you can use to check for an error -- it should contain code that will tell you where your problem lies.
In case that's an incorrect statement, you can always do a var_dump( $this->Email ); after you try to send an email. That will dump the entire contents of the object, so you can see if you have set attributes correctly, and it should help you find out what the error attribute is named.

Categories