Email list from sql practices - php

I have been using the following to get and email people in my database. The problem is now that the database has over 500+ members the script slows down and SHOWS each member email address in TO: field. I tried a suggestion on another site to use BCC instead but I was wondering isn't there a way to alter this to send the emails individually?
$sql = "SELECT * FROM users WHERE system = '101' AND mailing_list = 'yes'";
$result = mysql_query($sql) or die("Unable to execute<br />$sql<br />".mysql_error());
$row = mysql_fetch_array($result);
var_dump($row);
$to .= $row['email'] . "\r\n";
//send email

php's mail() is very inefficient, I suggest using something like phpmailer
from the manual:
Note:
It is worth noting that the mail() function is not suitable for larger
volumes of email in a loop. This function opens and closes an SMTP
socket for each email, which is not very efficient.
For the sending of large amounts of email, see the » PEAR::Mail, and »
PEAR::Mail_Queue packages.

You need to use PHPMailer as it is meant to be used for just this situation. the trouble with mail() is that it opens and closes a connection after each email. You obviously want to open 1 connection, send all your emails (one by one) and close the connection.
Something like below:
require("class.phpmailer.php");
$mail = new phpmailer();
$mail->From = "list#example.com";
$mail->FromName = "List manager";
$mail->Host = "smtp1.example.com;smtp2.example.com";
$mail->Mailer = "smtp";
#MYSQL_CONNECT("localhost","root","password");
#mysql_select_db("my_company");
$query = "SELECT full_name, email, photo FROM employee WHERE id=$id";
$result = #MYSQL_QUERY($query);
while ($row = mysql_fetch_array ($result))
{
// HTML body
$body = "Hello <font size=\"4\">" . $row["full_name"] . "</font>, <p>";
$body .= "<i>Your</i> personal photograph to this message.<p>";
$body .= "Sincerely, <br>";
$body .= "phpmailer List manager";
// Plain text body (for mail clients that cannot read HTML)
$text_body = "Hello " . $row["full_name"] . ", \n\n";
$text_body .= "Your personal photograph to this message.\n\n";
$text_body .= "Sincerely, \n";
$text_body .= "phpmailer List manager";
$mail->Body = $body;
$mail->AltBody = $text_body;
$mail->AddAddress($row["email"], $row["full_name"]);
$mail->AddStringAttachment($row["photo"], "YourPhoto.jpg");
if(!$mail->Send())
echo "There has been a mail error sending to " . $row["email"] . "<br>";
// Clear all addresses and attachments for next loop
$mail->ClearAddresses();
$mail->ClearAttachments();
}

Related

PHP mail error domain missing or malformed<EOL>

I'm trying to send a mail to a customers email thats set in my database.
$subject = 'Testing PHP Mail';
$txt = 'This mail is sent using the PHP mail function';
$headers = "FROM: test#gmail.com";
$query = ("SELECT email FROM ps_customer where id_customer = 2");
$result = $dbc->query($query);
$row = $result->fetch_assoc();
echo $row['email'];
$to_email = (string)$row;
//while ($row = $result->fetch_assoc()) {
// echo $row['email'];
// $to_email = (string)'$row <#>';
if (mail($to_email, $subject, $txt, $headers)) {
echo "send";
} else {
echo "failed";
}
this is my code that's need to send the email to the email out of the database.
but when i try to send it i get the error: : domain missing or
malformed
You only want the address, and it's the only field you're fetching, so I'd go with:
$query = ("SELECT email FROM ps_customer where id_customer = 2");
$result = $dbc->query($query);
$row = $result->fetch_row();
$to_email = $row[0];
No need to use an assoc array for this.
You've not mentioned it, but the messages you send will probably be rejected. You're sending via mail(), which means you are not sending through gmail's servers, but you're using a gmail from address. This is forgery and will mean your messages will be bounced or spam filtered. You can't solve this using mail() (other than by not using gmail for your from address); you would need to send using SMTP via gmail using PHPMailer (that you tagged this question with).

phpmailer with mysql results

I'm trying to use phpmailer to send out emails to each email address found in the database, but as a unique email. For some reason, it's sending duplicate emails, and it sends it out in as many copies as my query returns rows. So, if my query returns 5 rows, each recipient will receive 5 email (total emails sent is 25). I can't use the same email for multiple recipients because the email content is personalized.
What am I doing wrong with my code? Please help...
Here's my code:
$customers_query = "SELECT customer_name, customer_email, customer_id FROM customers";
$customers = mysql_query($customers_query);
if (!$customers) {
$message = 'Error notice: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
require_once('class.phpmailer.php');
// create an instance
while ($row = mysql_fetch_array($customers)) {
$email = $row['customer_email'];
$name = $row['customers_name'];
$id = $row['customer_id'];
$mail = new PHPMailer();
// use sendmail for the mailer
$mail->IsSendmail();
$mail->SingleTo = true;
$mail->IsHTML(true);
$mail->From = "noreply#domain.com";
$mail->FromName = "MyWebsite";
$mail->Subject = "Welcome to MyWebsite";
$mail->AddAddress($email);
$mail->Body = "Dear ".$name.", welcome to MyWebsite. Your ID is: ".$id.". Enjoy your stay.";
$mail->Send();
}
So, what am missing here? Why does it send that many emails?
Try this:
$mail->ClearAddresses(); after $mail->Send();
Try something like is below, you need to be counting your rows somehow so that it doesn't re-process them. Also, the AddAddress(); function is used to keep adding email addresses to the TO: field, so you need to call ClearAddresses(); in order to restart with a fresh set of recipients.
$customers_query = "SELECT customer_name, customer_email, customer_id FROM customers";
$customers = mysql_query($customers_query);
$count = mysql_num_rows($customers);
$result = mysql_fetch_array($customers);
$i = 0;
if (!$customers) {
$message = 'Error notice: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
require_once('class.phpmailer.php');
// create an instance
while ($i < $count) {
$email = mysql_result($result,$i,"customer_email");
$name = mysql_result($result,$i,"customers_name");
$id = mysql_result($result,$i,"customer_id");
$mail = new PHPMailer();
// use sendmail for the mailer
$mail->IsSendmail();
$mail->SingleTo = true;
$mail->IsHTML(true);
$mail->From = "noreply#domain.com";
$mail->FromName = "MyWebsite";
$mail->Subject = "Welcome to MyWebsite";
$mail->AddAddress($email);
$mail->Body = "Dear ".$name.", welcome to MyWebsite. Your ID is: ".$id.". Enjoy your stay.";
$mail->Send();
$mail->ClearAddresses();
$i++;
}
You can do one more thing, add one more extra field in the customer table, like is_email_sent, yes or no. Once sent email you can update specific row using primary key. so it will not send the same email to multiple time..

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.

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 !

The correct way to sendmail() with phpmailer using a db connection

I am trying to modify the phpmailer db mailer to use sendmail, would this code be correct below ?. I am trying to implement it into a website to email a clientbase of around 2-300 contacts.
Thanks :-)
<?php
require_once('./send/class.phpmailer.php');
//include("class.smtp.php"); // optional, gets called from within class.phpmailer.php if not already loaded
$mail = new PHPMailer(true); //defaults to using php "mail()"; the true param means it will throw exceptions on errors, which we need to catch
$body = file_get_contents('contents.html');
$body = eregi_replace("[\]",'',$body);
$mail->SetFrom('list#mydomain.com', 'List manager');
$mail->AddReplyTo('list#mydomain.com', 'List manager');
$mail->Subject = "PHPMailer Test Subject via smtp, basic with authentication";
$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();
}
?>
This should work, but make sure this feature is supported by the hosting company.

Categories