I have written a class in PHP which I use for sending mails making use of a Gmail account. This class in turn uses the PHPMailer library. The setup is WAMP 2.4 on Windows Vista. Using the microtime() function in PHP, I see that it takes anywhere between 5 to 6 seconds to send a single mail. Is it normal for a PHP script running on the kind of set up that I have to take as much as 5-6 seconds for a single mail going out. Here is code for the class.
<?php
require_once("phpmailer/class.phpmailer.php");
require_once("phpmailer/class.smtp.php");
class Mailer {
// Needs to be set per object
public $subject;
public $message;
public $to_name;
public $to;
private $mail; // This is the main mail object that'll be initialized
public function __construct() {
// Need to create a PHPMailer object in the constuctor and return it for use in this class.
$mail = new PHPMailer();
$from_name = "bleh";
$from = "bleh#gmail.com";
$username = "bleh";
$password = "bleh";
$mail->FromName = $from_name;
$mail->From = $from;
$mail->Username = $username;
$mail->Password = $password;
$mail->IsSMTP();
$mail->Host = "smtp.gmail.com";
// $mail->Port = 587; // Turns out, I dont need this one.
$mail->SMTPAuth = true; // gmail requires this
$mail->SMTPSecure = 'tls'; // gmail requires this
$this->mail = $mail;
}
function send() {
$mail = $this->mail; // The mail object
$mail->Subject = $this->subject;
$mail->Body = $this->message;
$mail->AddAddress($this->to, $this->to_name);
$result = $mail->Send();
return $result;
}
}
?>
Code used to test this -
$startTime = microtime(true);
require_once("mailer.php");
$mailer = new Mailer();
$mailer->subject = "Test";
$mailer->message = "Test";
$mailer->to_name = "My Name";
$mailer->to = "anemail#address";
$mailer->send();
echo "Time: " . number_format(( microtime(true) - $startTime), 4) . " Seconds\n";
It is very common for SMTP to take a long time - it's even used as an anti-spam measure in the form of greetdelay/tarpit mechanisms. RFC2821 section 4.5.3.2 allows up to a 5 minute delay before traffic starts. SMTP is not intended for interactive use (since it can't queue in that situation), and sending via SMTP during web page submission can suffer because of that. Sendmail or SMTP via an async process would avoid the issue.
In PHPMailer you can enable SMTP debug output and it will show you what's happening so you'll be able to see what's taking the time:
$mail->SMTPDebug = 2;
As mentioned in my comment, Gmail may be rate limiting you. There could also be some aspect of your network communication with Gmail that is causing the issue.
You can manually begin an SMTP conversation with Gmail from the command line. Watch for how long each step takes, and check for any codes / messages that may come back from Gmail indicating a problem.
For details on how to create a manual SMTP conversation see
Connecting to smtp.gmail.com via command line
Messages that come back will be Base64 encoded as indicated in that answer. You can use an online Base64 decoder to convert back to plain text.
Note: The link shows instructions for Linux. If you don't have a Linux server to test from, you can use Cygwin (for windows) or an OpenSSH for Windows package that does not require a full Cygwin install
I have faced to same problem and its getting around 30s to send the email.
The problem was system running PHP server got hang until the email is sent.
I tried many solutions but easiest way was start another PHP server locally on different port for handle the mail sending.
The main PHP server (system running server) will handed over the mail sending request to the mail PHP server and continue no the process.
Still 30s will take to send the email, but not effect to the main PHP server.
Related
So as the title implies
Im trying to send an email (one email) but the problem I'm facing is bizarre.
Whenever debug is turned on, email is sent only once.
But when debug is turned off, around 3 to 4 emails are sent at once.
NOTE: I'm using localhost not an actual server.
to diagnose the problem, I did the following:
1- used a md5 to generate random string in the "subject" to check whether email is sent with same contents or different. and the results were totally different. meaning, emails weren't duplicate but actually being sent couple of times.
2- opened the project in a browser with no extensions to make sure the problem wasn't in an extension loading my project page more than once. and the results were also similar to number 1, different "subject" also.
so, long story shot. i have no idea what causes this problem to happen. and why it only stop happening when debug is turned on.
NOTE: this is not my first time to use PHP mailer, but my first time to face this problem. I'm also using the latest version of PHP mailer (6.5.1)
Here is my entire code:
in PHP mailer file:
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;
require ABSPATH.'inc/phpmailer/script/src/PHPMailer.php';
require ABSPATH.'inc/phpmailer/script/src/Exception.php';
require ABSPATH.'inc/phpmailer/script/src/SMTP.php';
function SendEmail(){
$mail = new PHPMailer(true);
try {
//Server settings
$mail->SMTPDebug = SMTP::DEBUG_OFF;
$mail->SMTPAuth = true;
$mail->SMTPSecure = 'ssl';
$mail->isSMTP();
$mail->Host = '*****';
$mail->SMTPAuth = true;
$mail->Username = '*****';
$mail->Password = '*****';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
$mail->Port = 465;
$mail->SMTPAutoTLS = false;
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
$mail->ClearAllRecipients();
$mail->clearAttachments();
//Recipients
$mail->setFrom('*****', '******');
$mail->addAddress('*******', '*****');
$mail->addReplyTo('******', '******');
//Attachments
$mail->addAttachment(ABSPATH.'upload/dog.jpg', 'new.jpg');
//Content
$mail->isHTML(true);
$mail->Subject = md5(rand()); //This is how I'm checking whether it sends same email with same subject header or different ones. and it does send different ones
$mail->Body = 'This is the HTML message body <b>in bold!</b>'. md5(rand());
$mail->AltBody = "To view the message, please use an HTML compatible email viewer!";
$mail->ContentType = 'text/html; charset=utf-8\r\n';
$mail->send();
echo 'Message has been sent';
} catch (Exception $e) {
echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
}
and here is the file I'm using to call the function
<?PHP
// NO LOOP here
require_once(ABSPATH.'inc/phpmailer/phpmailer.php');
SendEmail();
As always, the first place to check is the docs.
Since you've already tried the random hash in the subject trick (well done on your logic!), you know that the problem is not that your script is sending more than one message, but that your script is being called repeatedly, and you should see evidence of that in your web server logs too. The usual reason for this is browser extensions which have a nasty habit of doing multiple submissions. Test that by using a clean browser with no extensions (e.g. use a browser you don't normally use, like Opera, Brave, or Chrome Canary).
Any requests that your browser is making should appear in the network tab of the dev console. On the server side you can either set up remote debugging to trigger breakpoints (tricky), or var_dump every request to a log so you get full details of what's calling the script.
BTW, you really shouldn't be disabling TLS verification. Fix the problem properly instead of hiding it; the troubleshooting guide has lots on that subject.
I had the same issue and solved by upgrading to the latest version of PHPMailer.
I've been trying to get my PhpMailer to work for over a week now.
I'm on a Windows machines, so I set up a "droplet" server with DigitalOcean (because they seem to have good step-by-step instructions) and then set up fake email accounts with ZohoMail (because it's free and I just need to test this.)
I've got breaks all over the three PhpMailer files I need (PhpMailerAutoload.php, class.phpmailer.php, and class.smtp.php). What I figured out is that I'm getting hung up on this line:
class.smtp.php line 1060 (or about since I've got breaks in there)
inside function get_lines:
$str = #fgets($this->smtp_conn, 515);
I put in more breaks, as below:
//*********Debug Code here
$test = $this->smtp_conn;
echo "\nContents of test var: \n";
var_dump($test);
echo "about to set str var \n";
$str = #fgets($test, 515);
echo "Contents of str var \n";
var_dump($str);
echo "\n out of debug code";
//***********End of debug code
After two minutes (2 minutes and 5 seconds to be precise) $test var_dumps just fine and "about to set str var" prints just fine.
But that's it. No more code executes.
I don't know what #fgets is. I don't see any documentation in the PHP manual for that, so I'm not sure where to go from here.
FIRST IDEA:
I checked on my php versions:
- server is running 5.5.9
- my PC is running 5.6.12
I'm guessing those are close enough.
SECOND IDEA:
I found that in the past there are a "==" vs "=" issue with this line of code, but that's clearly not the issue here.
THIRD IDEA:
I also read that some people fixed this problem by making sure that "php_openssl.dll" is enabled in their php.ini file.
In mine I have a line that reads:
extension = php_openssl.dll
So I think that's OK.
FOURTH IDEA:
Is my configuration wrong?
I'm using the following:
SMTP Host: smtp.zoho.com (should I get the IP address instead?)
SMTP Port: 465
and I think I have encryption and authentication turned on. (My code is at the end if that helps.)
FIFTH IDEA:
Start over using gmail to see if that gives me any clues, unless someone has a better idea.
function send_SMTP_email($email, $name, $subject, $msg) {
//SMTP needs accurate times, and the PHP time zone MUST be set
//This should be done in your php.ini, but this is how to do it if you don't have access to that
date_default_timezone_set('Etc/UTC');
require_once '/inc/phpmailer/PHPMailerAutoload.php'; // will load class.phpmailer.php and class.smtp.php itself
require_once '/inc/config.php';
//Create a new PHPMailer instance
$mail = new PHPMailer;
//Tell PHPMailer to use SMTP
$mail->isSMTP();
//Enable SMTP debugging, TO DO: Disable for production
// 0 = off (for production use)
// 1 = client messages
// 2 = client and server messages
$mail->SMTPDebug = 2;
//Ask for HTML-friendly debug output
$mail->Debugoutput = 'html';
//Set the hostname of the mail server
$mail->Host = SMTP_HOST;
//Set the SMTP port number - likely to be 25, 465 or 587
$mail->Port = SMTP_PORT;
//Whether to use SMTP authentication
$mail->SMTPAuth = true;
//Username to use for SMTP authentication
$mail->Username = SYSTEM_EMAIL;
//Password to use for SMTP authentication
$mail->Password = SYSTEM_PASSWORD;
//Set who the message is to be sent from
$mail->setFrom(SYSTEM_EMAIL, SYSTEM_NAME);
//Set an alternative reply-to address
$mail->addReplyTo(SYSTEM_EMAIL, SYSTEM_NAME);
//Set who the message is to be sent to
$mail->addAddress($email, $name);
//Set the subject line
$mail->Subject = $subject;
//Read an HTML message body from an external file, convert referenced images to embedded,
//convert HTML into a basic plain-text alternative body
//$mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__));
//Send HTML OR Plain Text
$mail->isHTML(true);
//Set body
$mail->Body = "<p>" . $msg . "</p>";
//Include plain text if non-HTML email reader
$mail->AltBody = $msg;
//Attach an image file
//$mail->addAttachment('images/phpmailer_mini.png');
$result = $mail->send();
//send the message, check for errors
//if (!$mail->send()) {
if (!$result) {
$return_val = "Mailer Error: " . $mail->ErrorInfo;
} else {
$return_val = "";
}
return $return_val;
}
I just had the same problem and finally found the problem. The default is set to TLS. Once I changed it to SSL with
$mail->SMTPSecure = 'ssl';
everything worked fine. Hopes this helps, if anyone else faces the same issue.
When using PHPMailer on localhost (Windows, XAMPP), email sends ok but the script hangs forever -- no refresh.
php's own mail() function works fine, and PHPMailer works fine using sendmail, so this is only a problem in SMTP mode.
Strangely, when stepping through with Xdebug,
I get "Fatal error: Maximum execution time of 0 seconds exceeded" in the console when I reach __destruct()
though I can step through this, which gives me the refresh and the error reflected in the browser. Also, once I've done this, I can refresh the browser and new emails will be sent normally and with no error and no hanging. Exit out of debugging mode and I return to the hanging behaviour.
Note: in php.ini:
max_execution_time=60
max_input_time=60
require_once "PHPMailerAutoload.php";
$to = "myemail#gmail.com";
$to_name = "Me";
$from_name = "fromName";
$from = "from#name.com";
$subject = "This is a test email from php " . strftime("%T", time());
$message = "phpmailer using smtp";
$mail = new PHPMailer();
$mail->IsSMTP();
$mail->SMTPDebug = 2;
$mail->Host = "# censored #";
$mail->Port = 587;
$mail->SMTPAuth = true;
$mail->SMTPSecure = 'tls';
$mail->Hostname = "myhost";
$mail->Username = '# censored #';
$mail->Password = '# censored #!';
$mail->FromName = $from_name;
$mail->From = $from;
$mail->addAddress($to, $to_name);
$mail->Subject = $subject;
$mail->Body = $message;
$result = $mail->send();
echo $result ? 'Sent' : 'Error: ' . $mail->ErrorInfo;
I have had similar issues when working on a development localhost server with PHPMailer. After much research the way that I overcome this was to manually require both the PHPMailer class and the SMTP class like:
require('../vendor/phpmailer/phpmailer/class.phpmailer.php');
require("../vendor/phpmailer/phpmailer/class.smtp.php");
As using the PHPMailerAutoload.php didn't fully require all the class needed and threw exceptions. Do you have a live server to test as I found a lot of answers like "works fine when live and fully deployed", this is a risky choice though.
I managed to overcome the "maximum execution time" by requiring the files manually. But the hanging is intermittent whilst using windows and XAMPP where sometimes it send straight away and other times it may take a while for the script to process. Not sure if this will work but it's worth a shot.
Further to this I investigated the "class.smtp.php" file within PHPMailer and found this:
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
if (substr(PHP_OS, 0, 3) != 'WIN') {
$max = ini_get('max_execution_time');
// Don't bother if unlimited
if ($max != 0 && $timeout > $max) {
#set_time_limit($timeout);
}
stream_set_timeout($this->smtp_conn, $timeout, 0);
}
Which defined in the comments above it states that "Windows does not support the timeout function". Maybe from this understanding it could help you eliminate possibilities?
The following script takes about 1.5 seconds to send an email as measured by the timers across the $mail->send() line. If I don't use smtp, it goes MUCH faster, however, some mail servers will block the incoming email.
What is causing the delay? If there is nothing that could be done about it, what would be a good solution to prevent the user from having to wait for it?
<?php
require_once ('../../application/classes_3rd/PHPMailer/PHPMailerAutoload.php');
class myPHPMailer extends PHPMailer
{
public function __construct()
{
$this->isSMTP();
$this->SMTPDebug = 0;
$this->Host = 587;
$this->Port = "smtp.gmail.com";
$this->SMTPSecure="tls";
$this->SMTPAuth = true;
$this->Username = "example#gmail.com";
$this->Password = "my_password";
}
}
try {
$mail = new myPHPMailer(true);
$mail->AddReplyTo('me#example.com');
$mail->SetFrom('me#example.com');
$mail->AddAddress('me#example.com', 'John Doe');
$mail->Subject = "My subject";
$mail->MsgHTML("Hello! Click this link https://www.google.com/");
$time=microtime(1);
$mail->Send();
echo(microtime(1)-$time);
} catch (phpmailerException $e) {
trigger_error($e->errorMessage(), E_USER_ERROR);
}
?>
When you use the isMail() or isSendmail() transport options in PHPMailer, it does not send the message immediately, but submits it to your local mail server, which frees up your web app and sends the message at its leisure. This usually incurs no network overhead, no encryption or authentication, and if it's a low-traffic server, it's probably doing little else and can accept the message very quickly.
SMTP was never really meant to be used interactively i.e. during submission of a web page, and it can indeed take a long time. It's a complex protocol with many round-trips and points where delays are likely, particularly with the likelihood of grey listing, greet delays, immediate spam filtering and more.
If you want to use SMTP and make it fast, use a nearby mail server (even localhost) as a relay that doesn't need encryption or authentication and does not apply spam filtering on outbound messages.
instead of use this:
$mail->IsSMTP();
Use this:
$mail->IsMail();
I was with same issue, SMTP can really slow you down.
I have created a PHP page, whereby having the page to send automatically to user, i tried using PHPMailer but it only says "SMTP ERROR: cannot access host or somthing like that "
here's my code:
PHPMailer x = new PHPMailer();
x->isSMTP();
x->Host = myhost;
x->Port = myport;
x->AddAddress(recipientAddress);
x->From = myEmail;
x->Username = username;
x->Password = password;
x.Send();
here is quick fix of your code
$mail = new PHPMailer();
$mail->IsMail();
$mail->setCharset = "UTF-8";
$mail->Host = "localhost";
// $mail->Port = "587"; you don't need it now
$mail->AddAddress("recipientAddress");
$mail->setFrom = "myEmail";
$mail->Subject = "Subject";
$mail->Username = "username";
$mail->Password = "password";
$mail->SMTPDebug = 2; // enables SMTP debug information (for testing)
// 1 = errors and messages
// 2 = messages only
$mail->Send();
so now you would get more debug messages and track your errors and fix them :)
update : okay that is easy :
The function $mail->IsMail(); indicates that the letter must be sent using mail() function. Other methods are:
IsSendmail - via sendmail command.
IsQmail - directly via qMail MTA.
IsSMTP - via SMTP server.
Try removing the isSMTP line so it will use the mail settings configured in PHP.
This looks that your SMTP settings on the www server are wrong.
Check if you can send the e-mail with the SMTP configuration you specified - if not:
is there a SMTP server running on myhost:myport?
Does it listen on the interface you're using to talk to it?
Is it configured to accept mail from your host?
Is it configured to accept mail for the recipients?