Use array of emails and names from database in PHPMailer - php

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"]}";
}
?>

Related

PHPMailer not sending to all emails in mailing list

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.

Please provide at least one recipient email address:-Mailer error while using php mailer

I'm using PHPMailer on my website, but it returns an error:
You must provide at least one recipient email address.
I've checked out the following pages looking for answers:
https://github.com/PHPMailer/PHPMailer/issues/441
https://github.com/PHPMailer/PHPMailer/issues/429
None of those solved my problem.
This is the way it's set up:
<?php
$conn=mysqli_connect("localhost","sar","siarth2");
mysqli_select_db($conn,"test");
$Email=$_REQUEST["Email"];
$query=mysqli_query($conn,"select * from user where Email='$Email'");
$row=mysqli_fetch_array($query,MYSQLI_ASSOC);
require 'PHPMailer-master/PHPMailerAutoload.php';
$mail = new PHPMailer();
$mail->Host = "ssl://smtp.gmail.com";
$mail->SMTPAuth = TRUE;
$mail->Username = "sidban5679#gmail.com";
$mail->Password = "password";
$mail->Port =466;
$mail->From = "sidban5679#gmail.com";
$mail->FromName = "Sidharth";
$mail->AddAddress($row["Email"]);
$mail->isHTML(true);
$mail->Subject = "Password";
$mail->Body = "<i>this is your password:</i>".$row["Password"];
$mail->AltBody = "This is the plain text version of the email content";
if(!$mail->send())
{
echo "Mailer Error: " . $mail->ErrorInfo;
}
else
{
echo "Message has been sent successfully";
}
SQL Code
INSERT INTO user (Password, FirstName, LastName, Email) VALUES
('friends34', 'Kaser', 'Baddal', 'banh5#gmail.com');
Check that if your $Email and $row['Email'] is returning any valid email address or not.
you can try once with a hard coded recipient.
$mail->AddAddress('receipient#example.com');
I guess from your code, $Email and $row['Email'] are same value. so if $Email=$_REQUEST["Email"]; is getting valid email, you can use -
$mail->AddAddress($Email);
On top of the wrong port number, SQL injection vulnerability, plain-text passwords, that you're using an outdated version of PHPMailer, and have based your code on an obsolete example, you're not doing any error checking on the email address. Try this:
if (!$mail->addAddress($row['Email'])) {
exit(htmlspecialchars($row['Email']) . ' is not a valid email address.');
}
(htmlspecialchars() is there to avoid adding an XSS vulnerability for a perfect score!)

What's the right workaround to send DIFFERENT messages to DIFFERENT recipients in PHPMailer

I am trying to send an email to multiple different BCC recipients.
Every recipient gets an identical text body BUT, he also needs to receive his own individual email in it.
I'm looping through a JSON to add emails with the $mail->addBCC() function.
And I need that the $body that is sent to every individual user will contain his own individual address.
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;
require 'src/Exception.php';
require 'src/PHPMailer.php';
require 'src/SMTP.php';
//*** -> $allUsers is a JSON
function sendemails_ex($allUsers, $subject, $body)
{
$emailFrom = "noreply#slandergold.com";
$emailFromName = "slandergold.com";
if ($allUsers=="" || $subject=="" || $body=="")
{
exit();
}
$smtpUsername = "abcdKLARK";
$smtpPassword = "1t%y$R5$4";
$mail = new PHPMailer;
$mail->CharSet = 'UTF-8';
$mail->isSMTP();
$mail->SMTPDebug = 0;
$mail->Host = "mail.slandergold.com";
$mail->Port = 26; //587; // TLS only
$mail->SMTPSecure = false; //'tls'; // ssl is depracated
$mail->SMTPAuth = false; //true;
$mail->Username = $smtpUsername;
$mail->Password = $smtpPassword;
$mail->setFrom($emailFrom, $emailFromName);
$arr = json_decode($allUsers,true);
foreach($arr as $item)
{
$mail->addBCC($item['Email'], $item['Fullname']);
}
$mail->isHTML(true);
$mail->Subject = $subject;
// ***********
// is there a way to make it
// so that every individual BCC recipient
// will get a body with the individual addition of:
// $userEmail = ?
// $body."<br />This is your email: ".$userEmail;
// ***********
$mail->msgHTML($body);
$mail->AltBody = 'HTML messaging not supported';
if(!$mail->send())
{
echo "Mailer Error: " . $mail->ErrorInfo;
}
else
{
echo "Message sent!";
}
}
As the comments say, you can’t send different emails to different recipients using BCC. You need to send each message individually, and the definitive way to do that is provided in the mailing list example provided with PHPMailer. There are also notes in the project wiki about how to send to lists efficiently.

How can I add a PHP script to Auto-respond with a "thank you" message

I'm php newbie that just figured out how to use php with phpmailer to send email addresses of my users to my email address to be added to a newsletter.
However, now I want to add a simple auto-respond script in php, so when users add their email to my guestlist it sends them an autoreply email to their email that says:
Thanks for signing up. [Picture of my logo] www.mysite.com
I've searched and searched, but I haven't been able to find a proper answer on how to create an autorespond script in php. Please let me know how I can accomplish this task. Thank you!
<?php
$email = $_REQUEST['email'] ;
require("C:/inetpub/mysite.com/PHPMailer/PHPMailerAutoload.php");
$mail = new PHPMailer();
// set mailer to use SMTP
$mail->IsSMTP();
$mail->Host = "smtp.comcast.net"; // specify main and backup server
$mail->SMTPAuth = true; // turn on SMTP authentication
$mail->Username = "myusername#comcast.net"; // SMTP username
$mail->Password = "*******"; // SMTP password
$mail->SMTPSecure = 'ssl'; // Enable TLS encryption, `ssl` also accepted
$mail->Port = 25;
$mail->From = $email;
// below we want to set the email address we will be sending our email to.
$mail->AddAddress("myemail#gmail.com", "Guestlist");
// set word wrap to 50 characters
$mail->WordWrap = 50;
// set email format to HTML
$mail->IsHTML(true);
$mail->Subject = "A new member wishes to be added";
$message = $_REQUEST['message'] ;
$mail->Body = $email;
$mail->AltBody = $email;
if(!$mail->Send())
{
echo "Message could not be sent. <p>";
echo "Mailer Error: " . $mail->ErrorInfo;
exit;
}
echo "Message has been sent";
$mail2 = new PHPMailer();
// set mailer to use SMTP
$mail2->IsSMTP();
$mail2->Host = "smtp.comcast.net"; // specify main and backup server
$mail2->SMTPAuth = true; // turn on SMTP authentication
$mail2->Username = "myusername#comcast.net"; // SMTP username
$mail2->Password = "*******"; // SMTP password
$mail2->SMTPSecure = 'ssl'; // Enable TLS encryption, `ssl` also accepted
$mail2->Port = 25;
$mail2->From = $email;
// below we want to set the email address we will be sending our email to.
$mail2->AddAddress("$email");
// set word wrap to 50 characters
$mail2->WordWrap = 50;
// set email format to HTML
$mail2->IsHTML(true);
$mail2->Subject = "Thank you for joining";
$message = "Please stay tune for updates" ;
$message = $_REQUEST['message'] ;
$mail2->Body = $message;
$mail2->AltBody = $message;
if(!$mail2->Send())
{
echo "Message could not be sent. <p>";
echo "Mailer Error: " . $mail2->ErrorInfo;
exit;
}
echo "Message has been sent";
?>
Update: 1
Ok, I figured out how to send auto-respond emails to users. However, now the users are receiving messages with their own email address and the name Root user
So what can I do to fix this problem so that users see my email address when they recevie auto-responses, and how can I make sure it says my name instead of root user?
Do not use the submitter's email address as the from address - it won't work as it looks like a forgery and will fail SPF checks. Put your own address as the From address, and add the submitter's address as a reply-to.
Using SMTPSecure = 'ssl' with Port = 25 is an extremely unusual combination, and very likely to be wrong. ssl/465 and tls/587 are more usual.
To send multiple messages, you do not need to create a second instance - just re-use the same one. You can reset any individual properties you want (such as Body) and clear addresses using $mail->clearAddresses(), then just call $mail->send() a second time.
It looks like you have based your code on an old example (try a new one) - make sure you are using latest PHPMailer - at least 5.2.10.
add:
echo "Message has been sent";
$mail = new PHPMailer();
$mail->From = 'myemail#gmail.com';
// below we want to set the email address we will be sending our email to.
$mail->AddAddress($email);
// set word wrap to 50 characters
$mail->WordWrap = 50;
// set email format to HTML
$mail->IsHTML(true);
$mail->Subject = "Thanks for joining ...";
$message = "Thanks for joining...";
$mail->Body = $email;
$mail->AltBody = $email;
$mail->Send();

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.

Categories