PHP: PEAR Mail connecting but not sending (no error)? - php

I'm using PEAR's Mail package to send email from my script. I'm pretty sure I have everything connected and declared properly, but when the script runs, it just connects then immediately disconnects to my Mail server without actually sending the email.
From my Postfix logs:
Nov 18 16:15:49 mailer postfix/smtpd[30346]: connect from xxx-xxx-xxx-xxx.static.cloud-ips.com[xxx.xxx.xxx.xxx]
Nov 18 16:15:49 mailer postfix/smtpd[30346]: disconnect from xxx-xxx-xxx-xxx.static.cloud-ips.com[xxx.xxx.xxx.xxx]
What gives?
<?php
require_once('Mail.php'); // loads in PEAR Mail package
$mailer_params['host'] = 'mailer.example.com';
$mailer_params['port'] = 25;
$mailer_params['auth'] = true;
$mailer_params['username'] = 'user#mailer.example.com';
$mailer_params['password'] = 'password';
$mail =& Mail::factory('smtp', $mailer_params);
$headers = array(
'From' => 'user#example.com',
'Reply-To' => 'user#example.com',
'Subject' => 'Test Email'
);
$message = "whatever";
$mail->send('Test <other.user#example.com>', $headers, $message);
?>
I know my Postfix server works, since I have several other applications using it without problems. The user credentials are the same in this script as they are for those other apps.
My Postfix server is using SASL_auth (configured with CRAM-MD5), if that helps. I wish I had an error message or something on either the PHP side or the Postfix side to go on, but all it does is just connect then disconnect with no other explanation.

I had this problem a few days ago. Try $mailer_params['auth'] = 'CRAM-MD5' and also for extra information, try $mailer_params['debug'] and run the script from the command line. If that still doesn't work, try $mail_params['auth'] = 'LOGIN'.
Hope this helps.

Here is the first thing I'd try, see if you can get an exception error from PHP:
<?php
try {
require_once('Mail.php'); // loads in PEAR Mail package
$mailer_params['host'] = 'mailer.example.com';
$mailer_params['port'] = 25;
$mailer_params['auth'] = true;
$mailer_params['username'] = 'user#mailer.example.com';
$mailer_params['password'] = 'password';
$mail =& Mail::factory('smtp', $mailer_params);
$headers = array(
'From' => 'user#example.com',
'Reply-To' => 'user#example.com',
'Subject' => 'Test Email'
);
$message = "whatever";
$mail->send('Test <other.user#xxx.com>', $headers, $message);
} catch (Exception $e) {
echo "Exception: " . $e->getMessage();
}
And I have some other questions, out of curiousity:
You mentioned your postfix server works with other applications, are they on the same server? Is this a remote request, or an application on the same server as the mail
Can you reverse engineer anything on the working server to see what's being done differently?
Are you sending email from the same domain as what's on the server?
Some of the basis behind question 1 and 3 is the fact that a great deal of hosts either block or put restrictions on mailing. This is because spammers will create accounts and abuse them until they are banned. This makes sending mail difficult for the rest of us honest people, but it happens every day.
I hope this gives some food for thought, reply back and let's see if we can find the problem.

Related

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

Send email reliably and handle errors robustly

I'm making my first site for a learning exercise as I've been a java back-end developer. I am setting up a user registration form and since this is going to be my user's first glimpse at my site, I want to make sure I handle things as robustly as possible. Through some trials I've come across and implemented almost all these solutions:
php's mail() function - this worked the first day i tested it and stopped working later. First time I realized sending mail wasn't a "given" simple task
pear mail class - implemented this tonight and is currently still working
pear smtp mail - read about this here. Makes me feel like I should be using smtp?
At this point I have realized sending email reliably is not quite as trivial as I originally thought. My question is what is the most reliable way to send mail, and what is the most robust way to handle exceptions? For instance if SMTP is the most reliable way, please explain why and provide a simple example with error handling.
For any of the errors that occur, are they errors where doing some automated retry would benefit? I understand that just because I send mail doesn't mean the person will get it, but I'm asking what the most robust solution is because I'm sure other people have done this 100 times over.
To prove I'm not just a lazy coder, this is what I've got so far which has been working - but I have no idea how robust this actually is (pear mail):
<?php } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
include('Mail.php');
include('Mail/mime.php');
$to = urldecode($_POST['email']);
if (preg_match('(\r|\n)', $to)) {
die('No email injection for you!');
}
$headers = array(
'From'=>'tag <me#mysite.com>',
'Subject'=>'Registration for mysite.com'
);
$text_body = 'boring text message';
$html_body = '<html>
<head><title>Welcome</title></head>
<body>
<p>slightly less boring message</p>
</body>
</html>';
//Utilize the mime class to generate mime body and add mime headers
$mime = new Mail_mime();
$mime->setTXTBody($text_body);
$mime->setHTMLBody($html_body);
$body = $mime->get();
$headers = $mime->headers($headers);
//Utilize the mail class to send the mime mail
$mail = Mail::factory('mail');
$mail->send($to, $headers, $body);
echo 'mail sent maybe?';
?>
EDIT:
Code sample using SMTP with error handling
<?php } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
include('Mail.php');
include('Mail/mime.php');
$to = $_POST['email'];
$to = urldecode($to);
if (preg_match('(\r|\n)', $to)) {
die('No email injection for you!');
}
$headers = array(
'From'=>'tag <me#mysite.com>',
'Subject'=>'Registration for mysite.com'
);
$text_body = 'boring text message';
$html_body = '<html>
<head><title>Welcome</title></head>
<body>
<p>slightly less boring message</p>
</body>
</html>';
//Utilize the mime class to generate mime body and add mime headers
$mime = new Mail_mime();
$mime->setTXTBody($text_body);
$mime->setHTMLBody($html_body);
$body = $mime->get();
$headers = $mime->headers($headers);
//Utilize the mail class to send the mime mail
$host = 'mail.mysite.com';
$port = '26';
$username = 'me#mysite.com';
$password ='myPassword';
$smtp = Mail::factory('smtp', array (
'host' => $host,
'port' => $port,
'auth' => true,
'username' => $username,
'password' => $password
));
$mail = $smtp->send($to, $headers, $body);
if (PEAR::isError($mail)) {
echo("<p>" . $mail->getMessage() . "</p>");
} else {
echo("<p>Message successfully sent!</p>");
}
?>
There are typically several steps involved in sending mail:
Application: Put mail into queue of local delivery agent
Delivery agent: Send mail to configured SMTP server
SMTP server: Send mail to destination mail server
User mail application: Fetch mail from mail server
User: Click on mail, read it
PHP's mail() function puts the mail into the queue of the local mail delivery agent on unix. You'll only get an error (return value false) if that does not work. You do not get notified when the agent cannot deliver the mail further or any of the steps 2-5.
Using a direct SMTP connection to your SMTP server at least gives you an if the mail cannot be delivered to your SMTP server, which is more information than you get with mail(). What you don't get is information if the mail does not get read or is simply filtered out into a spam folder, or if the remote mail account does not exist (3-5).
To get to know that the remote account exists, you need to either parse the error response mails ("Undelivered mail returned to sender), or implement the full remote server SMTP connection and sending yourself (step 3), which I would not recommend.
To find out if the mail has been read, you could embed a "web bug", a tiny (potentially clear) image that is displayed in the HTML mail and notifies you that the mail has been displayed. You can use this to put sent mails into a database and mark them as read when your web bug image URL gets called. Mails that did not get read in X days can be seen as "not read" or "failed" - but the user can also simply be on vacation :)
Reliability & robustness
Your own mail server (step 3) automatically tries to re-send mails when the remote user's mail server is down. If that does not work, you'll get mails like "Mail delivery delayed for 24 hours", and another mail when it stopped doing that.
So once the mail is on your mail server, you can be sure that this server will do everything it can to deliver it.

Getting error while trying to send mail in php

I am getting the error message as
Failed to connect to mailserver at &quot,localhost&quot, port 25,...
Contents of my php.ini file are
SMTP = localhost
smtp_port = 25
I used the following code
mail("xyz#gmail.com","test","msg","from abc#gmail.com");
You can't send outbound mails from localhost. To test the mail function, install mercury mail. It should come with xampp. Create emails for the localhost domains like steward#localhost. YOu could use aliases. Do your testing with that sending mails from one inbox to the other. You'd need a licensed version of mercury mail to send outbound messages.
Another option is to run your test on a remote server. Make sure the senders email is recognised by the sending server. Like you cannot be sending a gmail message using those settings you are displaying.
If sending from gmail is your objective, stackoverflow is full of answers already for how to send mails with gmail, even with codeigniter. Need some?
Here is what you ask for: Sending mail using gmail:
require_once "Mail.php";
$from = "<from.gmail.com>";
$to = "<to.yahoo.com>";
$subject = "Hi!";
$body = "Hi,\n\nHow are you?";
$host = "ssl://smtp.gmail.com";
$port = "465";
$username = "myaccount#gmail.com"; //<> give errors
$password = "password";
$headers = array ('From' => $from,
'To' => $to,
'Subject' => $subject);
$smtp = Mail::factory('smtp',
array ('host' => $host,
'port' => $port,
'auth' => true,
'username' => $username,
'password' => $password));
$mail = $smtp->send($to, $headers, $body);
if (PEAR::isError($mail)) {
echo("<p>" . $mail->getMessage() . "</p>");
} else {
echo("<p>Message successfully sent!</p>");
}
?> <!-- end of php tag-->
Get info here: https://stackoverflow.com/a/2748837/827224
You could even do more if you are using codeigniter or any PHP email class like PHPMailer
search email classes in phpclasses.org. An example is:
http://www.phpclasses.org/blog/package/9/post/1-Sending-email-using-SMTP-servers-of-Gmail-Hotmail-or-Yahoo-with-PHP.html
Finally, here is a class you can use:
http://www.phpclasses.org/package/7834-PHP-Send-e-mail-messages-Gmail-users-via-SMTP.html
Its clearly evident that there is no mail server running on localhost on port 25 (or a firewall is blocking it). Get and install a mailserver (there are a number of free ones for windows/linux/mac - just make sure your ISP allows it) and your script will run just fine.
I use this for testing which is quite nice: http://smtp4dev.codeplex.com/
Its a fake email server, that intercepts mail and dumps them for you to inspect and test on localhost.

How to send email in lotus notes using PHP

Need to send email using PHP via lotus notes. Notes is configured on my system. So just wanted if I could send email using PHP. Can anybody help with the code and configuration that I am supposed to do?
After reading replies from all of you, I tried to nail down things from my end. I could at least move one step ahead with all your help. I could figure out my mail server using GetEnvironmentString and its damn correct as also reflected in my lotus notes work space. But when I am trying to use the below code it just keeps on loading and finally returning nothing -
<?php
require_once "Mail.php";
$from = "abc#email.com";
$to = "abc#email.com";
$subject = "Test!";
$body = "Hi,\n\nTest?";
$host = "d23abcd";
$port = "1352";
$username = "abc#email.com";
$password = "mypassword";
$headers = array ('From' => $from,
'To' => $to,
'Subject' => $subject);
$smtp = Mail::factory('smtp',
array ('host' => $host,
'port' => $port,
'auth' => true,
'username' => $username,
'password' => $password));
$mail = $smtp->send($to, $headers, $body);
if (PEAR::isError($mail)) {
echo("<p>" . $mail->getMessage() . "</p>");
} else {
echo("<p>Message successfully sent!</p>");
}
?>
Am I committing some mistake here? I doubt
$host = "d23abcd";
$port = "1352";
If your Lotus Domino server has SMTP set up, you can use the Domino server as outgoing mail server (if PHP is able to send mail using a relay server).
Thanks a bunch for all your responses and replies. Finally, I am able to send mail using domino server. Would like to share few things that I came across -
Using $session->GetEnvironmentString("MailServer",True); figured out the server where session is an instance of COM object for Notes.NotesSession like new COM( "Notes.NotesSession" );
Secondly, I was trying with port 1352 which I got from netstat command for this particluar server process. But it didnt work and finally worked on 25 only.
Domino server was not accepting authentication, so used mail($to,$subject,$message,$headers); instead of $mail = $smtp->send($to, $headers, $body);
Happy that it worked. Thanks all for the help and suggestions.
Using your local Notes Client or a Notes Client installed on a "server" via COM to send mail is not a good idea. What you want is to send email from PHP via an SMTP server (which can be a Domino server, as Per pointed out).
Sending email via PHP is for example explained here and here. For the name of the server, the port used for SMTP and optional credentials, please contact your local Domino admin.

PHP mail hangs indefinitely - How to debug?

I've set up a simple mail system, which resembles the following:
$from = 'me <me#me.com>';
$to = 'you <you#you.com>';
$subject = 'subject';
$body = 'body';
$host = 'www.me.com';
$headers = array('From' => $from, 'To' => $to, 'Subject' => $subject);
$smtp = Mail::Factory('smtp', array('host' => $host, 'auth' => true,
'username' => 'username', 'password' => 'password'));
$mail = $smtp->send($to, $headers, $body);
if (PEAR::isError($mail)) {
throw new Exception('emailException');
}
When I try run the script however the browser (chrome) hangs indefinately. There is no exception thrown, no error page shown by the browser, it just sits and waits for a response (for over 12 minutes, longest I've left it).
My actual program is slightly different (the code is enclosed in a function with info passed as parameters). I have used static debugging and confirmed that the parameters getting passed in are correct, however it just never errors, so I can't even test any error information in $mail.
Does anyone know how I should go about debugging this?
Update I can confirm the page hangs when calling $smtp->send(...)
Debugging this could be done in the logfiles, there you might find some PEAR errors.
Futhermore you could debug by echo statements between each line of code so you know exactly where it hangs.
Long delays are likely to incur when trying to connect to a non existing host. So that's where I would start searching although 12 minutes is very very long. You need to use the PEAR class because you need to send through a designated SMTP server?
IME, more than 99% of reported errors regarding PHP's mail functionality are problems with mail and neither PHP nor it's interface.
Why are you trying to connect directly to the server instead of using PHP's mail()?
Do you have shell access to the machine? It makes the following simpler however you can do these from PHP.
Can you resolve the smtp server hostname?
Can you connect to port 25 on the smtp server?
How is authentication implemented? (should be included in the response to your EHLO)
If you've got shell access then route the connection via a logging proxy or capture usnig tcpdump/wireshark and see where the connection is getting stuck.
Most likely the mailserver is not implementing proper SMTP and the authentication is going awry.

Categories