PHPMailer not sending to all emails in mailing list - php

I'm using the example mailing list and trying to tailor it to work with my DB. The problem I'm having is it's only sending to one email from the list of users in the Table (the example table only has 5 users). The email is being sent to the last user listed in the table
//Passing `true` enables PHPMailer exceptions
//$mail = new PHPMailer(true);
$mail = new PHPMailer();
$body = file_get_contents('contents.html');
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->isSMTP();
$mail->Host = '####';
$mail->SMTPAuth = true;
$mail->SMTPKeepAlive = true; //SMTP connection will not close after each email sent, reduces SMTP overhead
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
$mail->Port = 465;
$mail->Username = '###';
$mail->Password = '###';
$mail->setFrom('###', 'List manager');
$mail->addReplyTo('###', 'List manager');
$mail->Subject = 'PHPMailer Simple database mailing list test';
//Same body for all messages, so set this before the sending loop
//If you generate a different body for each recipient (e.g. you're using a templating system),
//set it inside the loop
$mail->msgHTML($body);
//msgHTML also sets AltBody, but if you want a custom one, set it afterwards
$mail->AltBody = 'To view the message, please use an HTML compatible email viewer!';
//Connect to the database and select the recipients from your mailing list that have not yet been sent to
//You'll need to alter this to match your database
$connection = mysqli_connect($server, $loginsql, $passsql, "database_name")
or die("Could not connect to database");
$result = mysqli_query($connection, 'SELECT user_login, user_email, db_prefix FROM userstest');
foreach ($result as $row) {
try {
$mail->addAddress($row['user_email'], $row['user_login']);
} catch (Exception $e) {
echo 'Invalid address skipped: ' . htmlspecialchars($row['user_email']) . '<br>';
continue;
}
try {
$mail->send();
echo 'Message sent to :' . htmlspecialchars($row['user_email']) . ' (' .
htmlspecialchars($row['user_email']) . ')<br>';
} catch (Exception $e) {
echo 'Mailer Error (' . htmlspecialchars($row['user_email']) . ') ' . $mail->ErrorInfo . '<br>';
//Reset the connection to abort sending this message
//The loop will continue trying to send to the rest of the list
$mail->getSMTPInstance()->reset();
}
//Clear all addresses and attachments for the next iteration
$mail->clearAddresses();
$mail->clearAttachments();
}

All - thanks for the help. I actually figured it out. The email address for setFrom was not the same as the account that was sending it out so it wouldn't work sending out to external domains.

Related

ForEach loop values keeping previous values

I have a foreach loop from which i am sending emails for my customers.
I have 4 customers in my db 1,2,3,4
So according to foreach loop the loop will run for 4 times to send an email to every customer
But in 1st run it sends email to customer 1.
In 2nd run It is sending email to customer 1 and 2.
In thirdd run it is sending email to customer 1,2,3 and so on.
How can i make to send one email to one customer.
here is my code.
$list=$tmp_con->query("SELECT name,email FROM users WHERE user_type='$tp' AND subscribed='yes' AND verified='1'") or die($tmp_con->error);
$lis=array();
while($row=$list->fetch_array()){
$lis[] = $row;
}
foreach($lis as $lst){
$content = str_replace("{name}", $lst['name'], $mail_content);
$content=$content."".$append_unsub;
/**************************************************phpmailer class***********************/
//$mail->SMTPDebug = 3; // Enable verbose debug output
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = $mail_smtp_host; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = $mail_smtp_username; // SMTP username
$mail->Password = $mail_smtp_password; // SMTP password
$mail->SMTPSecure = $mail_smtp_enc; // Enable TLS encryption, `ssl` also accepted
$mail->Port = $mail_smtp_port; // TCP port to connect to
$mail->setFrom($mail_smtp_from_email, $mail_smtp_from_name);
$mail->addAddress($lst['email']); // Add a recipient
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = $mail_subject;
$mail->Body = $content;
if(!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent';
}
$lst['email']='';
/*************************************************php mailer ends here*************************************/
} ///foreach ends here
Create a new $mail object in the loop or even better reset the addresses in the loop. You've (probably) declared the $mail object outside the for loop.
So every time you call addAddress you're adding the email address of the user. The first time you're setting the email address of the first user, then the second time you're adding the email address to the list, so two email addresses. Third round the same, fourth round etc..
Edit: Creating $mail inside the loop fixes the problem, but isn't efficient. See Synchro's comment for a better way to create and send the email.
No need of creating an instance of PHPMailer in each and every loop. Use $mail->clearAddresses(); at the end of foreach loop to clear all the addresses.
Updated Code
$list = $tmp_con->query("SELECT name,email FROM users WHERE user_type='$tp' AND subscribed='yes' AND verified='1'") or die($tmp_con->error);
$lis = array();
while ($row = $list->fetch_array()) {
$lis[] = $row;
}
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = $mail_smtp_host; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = $mail_smtp_username; // SMTP username
$mail->Password = $mail_smtp_password; // SMTP password
$mail->SMTPSecure = $mail_smtp_enc; // Enable TLS encryption, `ssl` also accepted
$mail->Port = $mail_smtp_port; // TCP port to connect to
$mail->setFrom($mail_smtp_from_email, $mail_smtp_from_name);
foreach ($lis as $lst) {
$content = str_replace("{name}", $lst['name'], $mail_content);
$content = $content . "" . $append_unsub;
//$mail->SMTPDebug = 3;
$mail->addAddress($lst['email']); // Add a recipient
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = $mail_subject;
$mail->Body = $content;
if (!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent';
}
$mail->clearAddresses(); // Clear all addresses for next loop
}
References:
PHPMailer

Use array of emails and names from database in PHPMailer

I'm using PHPMailer to send an email from a form to all the emails in a MySQL database.
I've managed to get the form to send an email to each email but I'm now trying to use their name in the email sent to them meaning each email woud begin with "Hello, [their-name],".
I'm using an array to loop through the results of my database query and adding each email and name as $mail->addAddress('email#email.com, 'name');
I've tried saving the variable $name = $row['name'}; inside the while loop but it inputs the last name from the database into all the emails.
My question is: Is it possible to access the 'name' part of the function and use it each email. Or is it better to take their name from the database itself? And if so how would I go about doing that?
Also, when the email sends to each recipient, it shows all of the recipients in the "To:" field. This would be pretty bad for privacy. Is there a way to prevent this?
I'm fairly new to PHP and MySQL still so explanatory answers would be greatly appreciated.
Please find my code below.
<?php
// Take message value from form
$message = preg_replace("/\r\n|\r/", "<br />", $_REQUEST['message']);
$message = trim($message);
// Error reporting on
error_reporting(E_STRICT | E_ALL);
date_default_timezone_set('Etc/UTC');
// Require PHPMailer
require 'PHPMailer/PHPMailerAutoload.php';
$mail = new PHPMailer;
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->SMTPKeepAlive = true; // SMTP connection will not close after each email sent, reduces SMTP overhead
$mail->Port = 587;
$mail->Username = 'my#email.com';
$mail->Password = 'mypassword';
$mail->setFrom('myemail#email.com', 'Me');
$mail->addReplyTo('myemail#email.com', 'Me');
$mail->Subject = "Newsletter";
/* ----- Add address function below ----- */
// Require Database connection
require 'dbcon.php';
// SELECT email and name values from database
$query = "SELECT email, name FROM customers";
// Result = the database query
$result = $con->query($query);
// Get array of users email addresses and names.
while($row = $result->fetch_array())
{
// Add recipients from values found in database
$mail->addAddress($row["email"], $row["name"]);
}
/* ----- Add address function above ----- */
$mail->Body ="Hello, <br> <br> $message";
$mail->AltBody = $message;
if(!$mail->Send())
{
echo "Message could not be sent.";
echo "Mailer Error: " . $mail->ErrorInfo;
exit;
}
print 'Sent!';
?>
You are currently setting up to send a single email with several recipients. For security and etiquette, you should address the email to yourself (outside the loop):
$mail->addAddress('myemail#email.com', 'Me');
...and then add all of the recipients as BCC (inside the loop):
$mail->addBCC($row["email"], $row["name"]);
As for the name field. Add a debug line inside your loop and take a look at your output. Is the name field the same each time?
print "Adding recipient: {$row['email']} {$row['name']}";
If you want to sent several emails, one to each recipient, you need to instantiate a new email inside the loop each time.
[UPDATE]
If you want to send a single message to each recipient, then instantiate a new email each time (inside your loop):
<?php
// Take message value from form
$message = preg_replace("/\r\n|\r/", "<br />", $_REQUEST['message']);
$message = trim($message);
// Error reporting on
error_reporting(E_STRICT | E_ALL);
date_default_timezone_set('Etc/UTC');
// Require PHPMailer
require 'PHPMailer/PHPMailerAutoload.php';
// Require Database connection
require 'dbcon.php';
// SELECT email and name values from database
$query = "SELECT email, name FROM customers";
// Result = the database query
$result = $con->query($query);
// Get array of users email addresses and names.
while($row = $result->fetch_array())
{
// Instantiate a NEW email
$mail = new PHPMailer;
// Set the email settings
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->SMTPKeepAlive = true; // SMTP connection will not close after each email sent, reduces SMTP overhead
$mail->Port = 587;
$mail->Username = 'my#email.com';
$mail->Password = 'mypassword';
$mail->setFrom('myemail#email.com', 'Me');
$mail->addReplyTo('myemail#email.com', 'Me');
$mail->Subject = "Newsletter";
// Add recipient from values found in database
$mail->addAddress($row["email"], $row["name"]);
$mail->Body ="Hello, <br> <br> $message";
$mail->AltBody = $message;
if(!$mail->Send())
{
echo "Message could not be sent.";
echo "Mailer Error: " . $mail->ErrorInfo;
exit;
}
print "Sent mail to: {$row["email"]}, {$row["name"]}";
}
?>

Sending multiple emails with PHPmailer

Edit: I forgot I'd created the SendMail(); function myself, which is why the explanation doesn't mention at first what it does.
I'm having some trouble with PHPMailer (https://github.com/PHPMailer/PHPMailer) when attempting to send two emails, one directly after the other.
The script is almost completely 'out of the box', with only a few modifications such as a foreach loop to allow for multiple addresses, and everything still works perfectly.
However, if I attempt to call more than one instance of SendMail(); I get the error message:
Fatal error: Cannot override final method Exception::__clone() in .... online 0
Previously I was using the in-built mail(); function, which allowed me to use it as many times as I liked in quick succession , but it doesn't appear to be that simple with PHPmailer:
$to = me#me.com;
$to2 = me2#me2.com';
$headers = 'php headers etc';
$subject = 'generic subject';
$message = 'generic message';
mail($to, $subject, $message, $headers);
mail($to2, $subject, $message, $headers);
The above would result in two identical emails being sent to different people, however I can't easily replicate this functionality with PHPmailer.
Is there a way of stacking these requests so that I can send successive emails without it failing? Forcing the script to wait until the first email has been sent would also be acceptable, although not preferential.
As I mentioned I know it works when only one instance is called, but I don't seem to be able to re-use the function.
I haven't included the source code, although it is all available on the link provided above.
Thanks in advance
Edit as requested
// First Email
$to = array(
'test#test.com',
'test2#test.com',);
$subject = "Subject";
$message = $message_start.$message_ONE.$message_end;
sendMail();
// Second Email
$to = array(
'test#test.com',
'test2#test.com',);
$subject = "Subject";
$message = $message_start.$message_TWO.$message_end;
sendMail();
The above is how I want this to work, as it would work with mail();. The first email will work fine, the second will not.
SendMail() code
This is from the PHPmailer website, and is what is defined as SendMail();. The only difference from the example is the loop for AddAddress, and the inclusion of $to as a global variable.
$mail = new PHPMailer();
$mail->IsSMTP(); // set mailer to use SMTP
$mail->Host = "smtp1.example.com;smtp2.example.com"; // specify main and backup server
$mail->SMTPAuth = true; // turn on SMTP authentication
$mail->Username = "jswan"; // SMTP username
$mail->Password = "secret"; // SMTP password
$mail->From = "from#example.com";
$mail->FromName = "Mailer";
foreach($to as $to_add){
$mail->AddAddress($to_add); // name is optional
}
$mail->AddReplyTo("info#example.com", "Information");
$mail->WordWrap = 50; // set word wrap to 50 characters
$mail->AddAttachment("/var/tmp/file.tar.gz"); // add attachments
$mail->AddAttachment("/tmp/image.jpg", "new.jpg"); // optional name
$mail->IsHTML(true); // set email format to HTML
$mail->Subject = "Here is the subject";
$mail->Body = "This is the HTML message body <b>in bold!</b>";
$mail->AltBody = "This is the body in plain text for non-HTML mail clients";
if(!$mail->Send())
{
echo "Message could not be sent. <p>";
echo "Mailer Error: " . $mail->ErrorInfo;
exit;
}
echo "Message has been sent";
You haven't posted this code that lets me make this a complete conclusion, but from the Exception and the way you've defined an overriding class inside a function, you probably have class.phpmailer.php loading every time like this:
require('class.phpmailer.php');
or
include('class.phpmailer.php');
You should change that line to
require_once('class.phpmailer.php');
The reason you need to change it to require_once is so that PHP will not load the class file the second time when you try to create the new/second PHPMailer class. Otherwise, the line class PHPMailer throws the __clone() exception.
Added an example below:
<?php
/**
* This example shows how to send a message to a whole list of recipients efficiently.
*/
//Import the PHPMailer class into the global namespace
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
error_reporting(E_STRICT | E_ALL);
date_default_timezone_set('Etc/UTC');
require '../vendor/autoload.php';
//Passing `true` enables PHPMailer exceptions
$mail = new PHPMailer(true);
$body = file_get_contents('contents.html');
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->SMTPKeepAlive = true; // SMTP connection will not close after each email sent, reduces SMTP overhead
$mail->Port = 25;
$mail->Username = 'yourname#example.com';
$mail->Password = 'yourpassword';
$mail->setFrom('list#example.com', 'List manager');
$mail->addReplyTo('list#example.com', 'List manager');
$mail->Subject = 'PHPMailer Simple database mailing list test';
//Same body for all messages, so set this before the sending loop
//If you generate a different body for each recipient (e.g. you're using a templating system),
//set it inside the loop
$mail->msgHTML($body);
//msgHTML also sets AltBody, but if you want a custom one, set it afterwards
$mail->AltBody = 'To view the message, please use an HTML compatible email viewer!';
//Connect to the database and select the recipients from your mailing list that have not yet been sent to
//You'll need to alter this to match your database
$mysql = mysqli_connect('localhost', 'username', 'password');
mysqli_select_db($mysql, 'mydb');
$result = mysqli_query($mysql, 'SELECT full_name, email, photo FROM mailinglist WHERE sent = FALSE');
foreach ($result as $row) {
try {
$mail->addAddress($row['email'], $row['full_name']);
} catch (Exception $e) {
echo 'Invalid address skipped: ' . htmlspecialchars($row['email']) . '<br>';
continue;
}
if (!empty($row['photo'])) {
//Assumes the image data is stored in the DB
$mail->addStringAttachment($row['photo'], 'YourPhoto.jpg');
}
try {
$mail->send();
echo 'Message sent to :' . htmlspecialchars($row['full_name']) . ' (' . htmlspecialchars($row['email']) . ')<br>';
//Mark it as sent in the DB
mysqli_query(
$mysql,
"UPDATE mailinglist SET sent = TRUE WHERE email = '" .
mysqli_real_escape_string($mysql, $row['email']) . "'"
);
} catch (Exception $e) {
echo 'Mailer Error (' . htmlspecialchars($row['email']) . ') ' . $mail->ErrorInfo . '<br>';
//Reset the connection to abort sending this message
//The loop will continue trying to send to the rest of the list
$mail->getSMTPInstance()->reset();
}
//Clear all addresses and attachments for the next iteration
$mail->clearAddresses();
$mail->clearAttachments();
}
In addition to #Amr most excellent code.
In order to use this in a cron fasion, two adds are useful.
$mail-> SMTPDebug = true;
$mail-> Debugoutput = function( $str, $level ) {_log($str);};
The function _log is up to you. Writing to a file, to a database or wherever. I personally have reduced this to
$mail-> Debugoutput = function( $str, $level ) {if( $level===3 ) {_log( $str ); } };
to only write the more juicier messages
the solution is to reset recipients data like this:
$Mailer->clearAddresses()
use your own variable as an instance of PHPMailer (instead of $Mailer)
$Mailer->clearAddresses()
This is the solution to avoid multiple msj to be send to the same recipient.

Sending bulk e-mail using phpmailer

i am trying to send bulk email using phpmailer i have more than 10 email id's in my database when i click on send button then first email will go to one person, the second email sent will go to that same person plus another, the third one will go to those two plus one more, and so on. this is my coding please help me
<?php
$body=$_POST['message'];
$subject=$_POST['sub'];
//error_reporting(E_ALL);
error_reporting(E_STRICT);
date_default_timezone_set('America/Toronto');
require_once("class.phpmailer.php");
//include("class.smtp.php");
$mail = new PHPMailer();
$mail->IsSMTP(); // telling the class to use SMTP
$mail->Host = "stmp.gmail.com"; // SMTP server
$mail->SMTPDebug = 1; // enables SMTP debug information
// 1 = errors and messages
// 2 = messages only
$mail->SMTPAuth = true; // enable SMTP authentication
$mail->SMTPSecure = 'ssl';
$mail->Host = "smtp.gmail.com"; // sets GMAIL as the SMTP server
$mail->Port = 465; // set the SMTP port for the GMAIL server
$mail->CharSet = "big5";
$mail->Username = "abc#gmail.com"; // GMAIL username
$mail->Password = "**********"; // GMAIL password
$mail->SetFrom("abc#gmail.com", ''); // set reply id
$mail->Subject = ($subject); // subject
$mail->MsgHTML("$body"); // message
$mail->AddAddress($address, "abc");
$con=mysql_connect("localhost","root","") or
die("could not connect:".mysql_error());
mysql_select_db("bulkemail");
$qry=mysql_query("SELECT * FROM email_id", $con);
if(!$qry)
{
die("Query Failed: ". mysql_error());
}
while($row = mysql_fetch_array($qry))
{
$id= $row["email"];
$address = ($id);
$mail->AddBcc($id);
$mail->send();
if(!$mail->Send()) {
echo "Mailer Error: " . $mail->ErrorInfo;
}
else {
echo "Message sent!";
}
}
?>
Remove $mail->send(); and move if(!$mail->Send()) to outside the while($row ..) loop
while($row = mysql_fetch_array($qry)){
$id= $row["email"];
$address = ($id);
$mail->AddBcc($id);
} // end the while loop
// remove $mail->send(); as it is a duplicate of if(!$mail->Send())
if(!$mail->Send()) {
echo "Mailer Error: " . $mail->ErrorInfo;
}
else {
echo "Message sent!";
}
I had used phpmailer for mass mailing and I had same problem.
while($row = mysql_fetch_array($qry)){
$id= $row["email"];
$address = ($id);
$mail->AddBcc($id);
//imo if should be in the while loop.
if(!$mail->Send()) {
echo "Mailer Error: " . $mail->ErrorInfo;
}
else {
echo "Message sent!";
//I added this function down there so that old address would be removed but in the new loop, new one will be added.
$mail-> ClearAddresses();
}
} // end the while loop
This works for me.
In your case, you are adding a new BCC to the list of all BCC already send in every repeat of the loop.
Like "kworr Sep 27 '13 at 18:36 " said, you need to create new instance for every sending in the loop.
Or you need to put
$mail->send();
out of the loop.

PHP - Query database for pending messages and call PHPmailer without refresh

I am using phpMailer, and i have a database table "list" with columns id|name|email|status.
What i am doing currently is using the phpMailer example
date_default_timezone_set('America/Toronto');
require_once('../class.phpmailer.php');
//include("class.smtp.php"); // optional, gets called from within class.phpmailer.php if not already loaded
$mail = new PHPMailer();
$body = file_get_contents('contents.html');
$body = eregi_replace("[\]",'',$body);
$id = $_GET['id'];
$mail->IsSMTP(); // telling the class to use SMTP
$mail->Host = "smtp1.xample.com;smtp2.xample.com";
$mail->SMTPAuth = true; // enable SMTP authentication
$mail->SMTPKeepAlive = true; // SMTP connection will not close after each email sent
$mail->Host = "mail.example.com"; // sets the SMTP server
$mail->Port = 25; // set the SMTP port for the GMAIL server
$mail->Username = "no-reply#example.com"; // SMTP account username
$mail->Password = "password"; // SMTP account password
$mail->SetFrom('no-reply#example.com', 'Honda example');
$mail->AddReplyTo('no-reply#example.com', 'Honda example');
$mail->Subject = "PHPMailer Test Subject via smtp, basic with authentication";
#MYSQL_CONNECT("localhost","root","password");
#mysql_select_db("osher");
$query = "SELECT full_name, email, photo FROM employee WHERE id=$id";
$result = #MYSQL_QUERY($query);
while ($row = mysql_fetch_array ($result)) {
$mail->AltBody = "To view the message, please use an HTML compatible email viewer!"; // optional, comment out and test
$mail->MsgHTML($body);
$mail->AddAddress($row["email"], $row["full_name"]);
$mail->AddStringAttachment($row["photo"], "YourPhoto.jpg");
if(!$mail->Send()) {
echo "Mailer Error (" . str_replace("#", "#", $row["email"]) . ') ' . $mail->ErrorInfo . '<br />';
} else {
echo "Message sent to :" . $row["full_name"] . ' (' . str_replace("#", "#", $row["email"]) . ')<br />';
}
// Clear all addresses and attachments for next loop
$mail->ClearAddresses();
$mail->ClearAttachments();
}
Now the code above is db-email.php Where in if my table, email has over 100 entries with status as pending, i want to be able to using php. select each rows id and call db-email.php?id=xx (where x is the id) hence the email gets sent.
This works fine, if its done manually.
i needed you guys to help me, how best I can automate this process, that is to be able to push this 100 emails (without having to refresh the page)
assuming, I am on email.php where I can probably hit (a button) and it would simply start processing, each of the row in the email table, (instead of echo'n the result) I will be updating the database with status to = 'sent'
I am not sure if I have been very clear on what I want to ask, Please do help friends.
I believe someone with expertise in jQuery/AJAX or something could help me achieve this task :)
I'm not sure what your trying to do but, you can't do anything with databases or servers via javascript or jquery because there executed in the browser and not on the server.
You could use ajax to call certain .php files on the server with some parameters to do your job !

Categories