I need assistance with sending bulk email.
This is this scanario.
A dropdown contains the categories of emails to be fetched. The selected (value) is then passed through a function that obtains all the emails per the selected value from db. And the emails passed to the mailer's addAddress method.
The sql query works fine but my headers show only the selected value from the network session and not all the returned emails. I am including both php codes and the ajax codes and also the response headers.
PHP block
$accountid = $_POST['accountid'];
$selectedstatus = $_POST['bulkrecipients']; //From dropdown
$emailtype = $_POST['emailtype'];
$subject = sanitize_text($_POST['bulksubject']);
$message = sanitize_text($_POST['bulkmessage']);
//Pass recipientemails to function and extract individual emails.
$getemails = getAllEmailsFromStatus($selectedstatus , $_SESSION['username']);
$name = 'Tester';
$mail = new PHPMailer;
$mail->isSMTP();
$mail->SMTPKeepAlive = true;
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = "";
$mail->Password = '';
$mail->Port = 465;
$mail->SMTPSecure = "ssl";
$mail->isHTML(true);
$mail->setFrom('testproject222', $name);
$mail->Subject = ("$subject");
$mail->Body = $message;
foreach ($getemails as $row) {
try {
$mail->addAddress($row['email']);
} catch (Exception $ex) {
echo 'Invalid address skipped: ' . htmlspecialchars($row['email']) . '<br>';
continue;
}
try {
if ($mail->send()) {
$status = "success";
$response = "Email is sent";
//Save the contact details to db.
saveAllEmployerEmails($accountid , $subject, emailtype, $message );
} else {
$status = "failed";
$response = 'Something is wrong ' . $mail->ErrorInfo;
}
exit(json_encode(array("status" => $status, "response" => $response)));
} catch (Exception $ex) {
echo 'Mailer Error (' . htmlspecialchars($row['email']) . ') ' . $mail->ErrorInfo . '<br>';
$mail->getSMTPInstance()->reset();
}
$mail->clearAddresses();
$mail->clearAttachments();
}
Ajax
function sendBulk() {
var url = "./inc/emailjobs.php";
var accountid = $("#accountid");
var emailtype = $("#emailtype");
var recipientemails = $("#bulkrecipients");
var bulksubject = $("#bulksubject");
var bulkmessage = $('#' + 'bulkmessage').html( tinymce.get('bulkmessage').getContent() );
if (isNotEmpty(recipientemails) /*&& isNotEmptyTextArea("bulkmessage")*/) {
$.ajax({
url: url,
method: 'POST',
cache: false,
dataType: 'json',
beforeSend: function () {
$('#bulksendbtn').text("Sending...");
},
data: {
accountid: accountid.val(),
emailtype: emailtype.val(),
bulksubject: bulksubject.val(),
bulkrecipients: recipientemails.val(),
bulkmessage: bulkmessage.val()
}
, success: function (response) {
$('#bulkemailForm')[0].reset();
$('.bulksendmessage').text("Emails Sent.");
$('#bulksendbtn').text("Sent");
},
});
}
}
Response Form header data
accountid: 2
emailtype: bulk
bulksubject: Test
bulkrecipients: shortlisted
bulkmessage: <p>Testing... </p>
Instead of the 'shortlisted' for bulkrecipients, I expect the email addresses. I was hoping to see 2 returned emails. The 'shortlisted' is supposed to be used to obtain the emails for that category (shortlisted).
Your code looks generally correct, but this is confusing:
$mail->setFrom('Test', $name);
//$mail->From = ("$email");
$email isn't defined, and Test is not a valid from address. I have a suspicion you're trying to use an arbitrary user-submitted email address as the from address. That will not work with Gmail because Gmail does not allow setting arbitrary from addresses; it will only let you send as the account owner (what you put in Username), or aliases that you preset in gmail settings. If you try to use anything else, it will simply ignore it and use your account address instead. Is this what you meant by "only the selected value from the network session"?
It's entirely reasonable for gmail to do this since almost by definition anything other than your account address is likely to be forgery, and nobody likes that.
If you want to send email where replies will go to a user-submitted address, use your own address in the from address, and use the user-submitted address as a reply-to. See the contact form example provided with PHPMailer for how to do that.
Related
The script im going to present is quite dificult to understand, but I will explain the basic idea bellow.
<?php
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
require_once 'apps/PHPMailer/src/Exception.php';
require_once 'apps/PHPMailer/src/PHPMailer.php';
require_once 'apps/PHPMailer/src/SMTP.php';
include_once('apps/HTMLDOMParser/simple_html_dom.php');
require_once("../db.php");
function clear($var) {
$var = NULL;
unset($var);
}
// Time when emails were sent last time
$result_laststamp = $conn->prepare("SELECT sent FROM nl_campaigns_emails ORDER BY sent DESC LIMIT 1", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$result_laststamp->execute();
if($result_laststamp->rowCount() > 0) {
while($row_laststamp = $result_laststamp->fetch(PDO::FETCH_ASSOC)) {
// data for first qeued campaign
$result_campaign = $conn->prepare("SELECT id,name,text,amount,period,smtp,user FROM nl_campaigns WHERE status='1' ORDER BY id ASC LIMIT 1", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$result_campaign->execute();
if($result_campaign->rowCount() > 0) {
while($row_campaign = $result_campaign->fetch(PDO::FETCH_ASSOC)) {
// SMTP Data
if($row_campaign['smtp']==1 && $row_campaign['user']>0) {
$result_smtp = $conn->prepare("SELECT * FROM admin_logins WHERE id=:id LIMIT 1", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$result_smtp->execute(array(":id"=>$row_campaign['user']));
if($result_smtp->rowCount() > 0) {
while($row_smtp = $result_smtp->fetch(PDO::FETCH_ASSOC)) {
// Check if its time to send next group of emails
if($row_laststamp['sent'] < (time()-($row_campaign['period']*3600))) {
// get email addresses, send, and edit timestmap in db when they were sent
$result_emails = $conn->prepare("SELECT id,email FROM nl_campaigns_emails WHERE (id_campaign=:id_campaign AND sent='0') ORDER BY id ASC LIMIT ".$row_campaign['amount'], array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$result_emails->execute(array(":id_campaign"=>$row_campaign['id']));
if($result_emails->rowCount() > 0) {
$array_email_ids = array();
while($row_emails = $result_emails->fetch(PDO::FETCH_ASSOC)) {
try {
$mail = new PHPMailer(true);
$mail->CharSet = 'UTF-8'; // UTF8 Encoding
$mail->Encoding = 'base64'; // Needs to be set with UTF8
//$mail->SMTPDebug = SMTP::DEBUG_SERVER; // Enable verbose debug output
$mail->isSMTP(); // Send using SMTP
$mail->Host = "smtp.somedomain.com"; // Set the SMTP server to send through
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = "noreply#somedomain.cz"; // SMTP username
$mail->Password = "somepassword"; // SMTP password
$mail->SMTPSecure = "tls";
$mail->Port = 587; // TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
//Sender
$mail->setFrom($row_smtp['email'], 'somename');
$mail->addReplyTo('info#somedomain.cz', 'somename');
$mail->Sender = 'noreply#somedomain.cz';
// Recipient
$mail->addAddress($row_emails['email']);
// Attachments
//$mail->addAttachment('/var/tmp/file.tar.gz'); // Add attachments
//$mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // Optional name
$bottom_text = "<p align=center style=\"font-size:11px; font-family:Arial; color:#8b8b8b;\">This email was sent to address ".$row_emails['email'].".<br>";
$bottom_text .= "To unsubscribe you can click to unsubscribe.</p>";
$bottom_text .= "<img src=\"http://www.somedomain.cz/view.php?id_campaign=".$row_campaign['id']."&id_email=".$row_emails['id']."\" style=\"visibility: hidden;\">";
// YOUTUBE LINK
$text = new simple_html_dom();
$text->load($row_campaign['text']);
foreach($text->find('iframe') as $element) {
$youtubeid = substr($element->src, strrpos($element->src, "/")+1);
// Create image instances
$video = imagecreatefromjpeg('https://img.youtube.com/vi/'.$youtubeid.'/maxresdefault.jpg');
$button = imagecreatefrompng('../images/youtube_play.png');
$video = imagescale($video, $element->width, $element->height);
$button = imagescale($button, imagesx($video)/7.5);
imagecopy($video, $button, imagesx($video)/2-imagesx($button)/2, imagesy($video)/2-imagesy($button)/2, 0, 0, imagesx($button), imagesy($button));
// Output and free from memory
imagejpeg($video, "../images/campaigns/videos/".$youtubeid.".jpg", 95);
imagedestroy($video);
imagedestroy($button);
unset($video);
unset($button);
$element->outertext = '<img src="http://www.somedomain.cz/images/campaigns/videos/'.$youtubeid.'.jpg" width="'.$element->width.'" height="'.$element->height.'">';
}
$row_campaign['text'] = (string)$text;
$text->clear();
clear($text);
// URL LINK FOR CLICKER ANALYZER
$doc = new simple_html_dom();
$doc->load($row_campaign['text']);
foreach ($doc->find('a') as $a) {
$a->href = 'http://www.somedomain.cz/clicker.php?id_campaign='.$row_campaign["id"].'&id_email='.$row_emails["id"].'&url='.urlencode($a->href);
}
$row_campaign['text'] = (string)$doc;
$doc->clear();
clear($doc);
// Content
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = $row_campaign['name'];
$mail->Body = $row_campaign['text'].$bottom_text;
$mail->AltBody = strip_tags($row_campaign['text']);
// MessageID
$data = array(
'campaign_id' => str_pad($row_campaign['id'], 6, '0', STR_PAD_LEFT),
'email_id' => str_pad($row_emails['id'], 11, '0', STR_PAD_LEFT),
'sent' => time(),
);
$messageId = '<'.base64_encode(json_encode($data)).'#www.somedomain.cz>';
$mail->MessageID = $messageId;
$mail->addCustomHeader('In-Reply-To', $messageId);
clear($data);
// SEND Email
$mail->send();
}
catch (Exception $e) {
echo "Emails were not send because: {$mail->ErrorInfo}";
die();
}
// ADD sent email to array
array_push($array_email_ids, $row_emails['id']);
// UPDATE the "sent" stamp
$update = $conn->prepare("UPDATE nl_campaigns_emails SET sent=:sent WHERE id=:id");
try { $update->execute(array(":id"=>$row_emails['id'], ":sent"=>time())); }
catch(Exception $error) { die($error->getMessage()); }
clear($update);
clear($mail);
}
clear($result_emails);
// CHECK IF STATUS COULD BE CLOSED
$result_emails_sent = $conn->prepare("SELECT id FROM nl_campaigns_emails WHERE (id_campaign=:id_campaign AND sent='0') ORDER BY id", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$result_emails_sent->execute(array(":id_campaign"=>$row_campaign['id']));
if($result_emails_sent->rowCount() == 0) {
$update = $conn->prepare("UPDATE nl_campaigns SET status=:status WHERE id=:id");
try { $update->execute(array(":status"=>3, ":id"=>$row_campaign['id'])); }
catch(Exception $error) { die($error->getMessage()); }
clear($update);
}
clear($result_emails_sent);
// Print the result
echo "<div style=\"color:#1b8d3d; text-align:center; font-size:25px; font-family:Arial;\">Sent total: ".count($array_email_ids)." emails.</div>";
echo "<center>REFRESH</center>";
}
}
else {
echo "<div style=\"color:#1b8d3d; text-align:center; font-size:25px; font-family:Arial;\">Next emails can be send at: ".date("j.n.Y H:i:s", $row_laststamp['sent']+($row_campaign['period']*3600))."</div>";
echo "<center>REFRESH</center>";
die();
}
}
}
else { die("error resolving SMTP"); }
clear($result_smtp);
}
}
clear($result_campaign);
}
else {
echo "<div style=\"color:#1b8d3d; text-align:center; font-size:25px; font-family:Arial;\">No campaign is running</div>";
echo "<center>REFRESH</center>";
die();
}
}
}
clear($result_laststamp);
clear($conn);
?>
the script looks quite huge, but at the end its simple logic:
get the last time emails were sent (for example $lastTimeSent)
get the data of the opened queued campaign (for example $dataCampaign)
get SMTP data to be used for sending emails (for example $SMTP)
checks if current timestamp time() is bigger then $lastTimeSent+allowed_period (because Im allowed to send 200 emails every 20mins)
loop the phpmailer, send emails separately (each time add one email to send)
and the problem is, that if I run the script inside nonallowed time period (so im not following rule of 200 emails in 20 mins), all works fine and script will evaluate this as false:
if($row_laststamp['sent'] < (time()-($row_campaign['period']*3600)))
$row_laststamp['sent'] is the timestmap of last email sent ($lastTimeSent)
$row_campaign['period'] is allowed period to send the email (value is actually 0.33 as in hours its 20 minutes), and im multiplying it by 3600 to recalculate to seconds so I can compare
so basicaly will jump and do stuff only from ELSE statement as its logical and its OK behaviour
However, when im outsode of the period so the same statement would evaluate as TRUE, the very strange behaviour happens.
The script will be looping and sending emails as it should, however instead of sending 200 emails as its the value of $row_campaign['amount'], it actually sends 64 (sometimes 65 emails) and then it wont echo Sent total: ".count($array_email_ids)." emails as it should logicaly, but also shows again the ELSE output *Next emails can be send at: ".date("j.n.Y H:i:s", $row_laststamp['sent']+($row_campaign['period']3600))..
So Im dealing with the problem that its shows the IF and ELSE output at once...
In other words, when statement *if($row_laststamp['sent'] < (time()-($row_campaign['period']3600))) is TRUE, it will partialy run the loop of try {} (only 65 times out of 200) and then shows the ELSE {} anyway...
BUT !!! if I remove/comment the line $mail->send(); then ALL works as expected !!!!! (unless emails are sent of course).
I was checking the memory status if im not getting out of memory and found out the maximum in final loop is about 24MB (when limnit is set to 256MB), also execution time is around 10second when I have set 120s.
so basicaly PHPMailer wont send more then 200 emails in loop when sending just one each time?
I wouldnt mind to send them all together and not looping it, however i dont want them to be seen in "TO" header of email, and if I use BCC instead, then (at least in gmail) it jumps to spam.
Any ideas?
EDIT:
I have simplified the script, made the adjustment according to https://github.com/PHPMailer/PHPMailer/wiki/Sending-to-lists
also i did place the debugger $mail->SMTPDebug = SMTP::DEBUG_SERVER; to see whats happening, and its interesting that the message from client to server suddently stop in the middle... no responce from the server, so the transfer just stops in the middle...
the very last line is not even finished and it just:
2020-09-02 17:06:40 CLIENT -> SERVER: NTI1MjUyNTNGaWRfY2FtcGFpZ24lMjUyNTI1MjUyNTI1MjUyNTI1MjUyNTI1MjUyNTI1MjU
so the comunication just stops from no reason, no server reply that its sent or not, nothing...
anyone has an idea?
so the error at the end was realy that I was not clearing recipients after each send(),
therefore first email was send to 1 recipient and each loop was 1 added but previous was not cleared...
clearing recipients after each loop fixed the problem
I am coding on a system where the admin should be able to click a button and send a mail to all users. When i click the a href and redirect with type = 2 it sends the mail to all accounts but the content which is supposed to be dynamic just returns the email of the last user in the array.
<?php
include "core/init.php";
error_reporting(E_ALL);
date_default_timezone_set('Etc/UTC');
require 'phpmailer/PHPMailerAutoload.php';
$mail = new PHPMailer;
$mail->isSMTP();
$mail->SMTPDebug = 0;
$mail->Debugoutput = 'html';
$mail->Host = 'smtprotocl';
$mail->Port = 587;
$mail->SMTPSecure = 'tls';
$mail->SMTPAuth = true;
$mail->Username = "mymail#mail.dk";
$mail->Password = "password";
$mail->CharSet = 'UTF-8';
$mail->setFrom('mymail#mail.dk', 'nameofmailholder');
if ($_GET["type"]) {
if ($_GET["type"] == 2){
$confirmede = 0;
$getVendorc = $db->prepare("SELECT * FROM db");
$getVendorc->execute();
$vresultc = $getVendorc->get_result();
$getVendorc->store_result();
while ($rowing = $vresultc->fetch_assoc()) {
$removeSpace = explode(" ", decrypt($rowing["email"]));
$Uemail = implode("+", $removeSpace);
$mail->addReplyTo($Uemail);
$mail->addAddress($Uemail);
}
$mail->isHTML(true);
$mail->Subject = 'welcome';
$mail->Body = '<button >Bekræft email</button>';
} else {
urlLocation("index");
}
}
$mail->AltBody = 'aa';
if($mail->send()) {
urlLocation("../../index");
}?>
Either create the email (using PHPMailer functions) and send it INSIDE the loop (which is what you should do), or do the following if you want to send one email to all recipients at once (without revealing emails to anyone, because it's BCC). I don't recommend this, but I suppose it could work.
$mail->addAddress("fake#address.com");
$mail->addBCC($email1, $email2, $email3, $email4);
That should work for sending the same email to multiple recipients, in one email without revealing all of the emails to everyone.
Personally, I use wuMail... It makes using PHPMailer a lot easier, especially with SMTP. Here's my setup, with login details changed obviously... I'll explain how it works below, but you would need to download wuMail (link at bottom) so that the files (for PHPMailer) are referenced correctly by config.php & wuMail.php... The code blocks below are references, but can't be used standalone without the rest of the wuMail download.
The first thing that happens is that we set the system defaults... These are used in case certain email parameters are not supplied to wuMail(). This is a fail safe, in case you want a default to address in case part of the system attempts to use wuMail() without supplying to address.. This would let you discover those types of bugs quickly.
The following is the code in config.php... You require config.php in any file that you want to use wuMail() function in (to send mail). Config will set the settings in advance & then bring in the wuMail.php file itself. So don't include the wuMail.php file, just config.php!
<?php
/*
NOTE: These settings have been prepared by
WUBUR.COM / WUBUR LLC / BILLY LOWERY / WILL PASSMORE
*/
# DO NOT REMOVE:
$wuMail_Config = new stdClass();
//SENDER CONFIG SETTINGS - YOU CAN CHANGE THESE:
// ----> Note: This current configuration has a form sending to the same address each time
// ----> This could obviously be adapted to allow for emails being sent elsewhere
$wuMail_Config->SiteName = 'Wubur.com';
//SERVER CONFIG SETTINGS - YOU CAN CHANGE THESE:
$wuMail_Config->isSMTP = true; // Set mailer to use SMTP (TRUE / FALSE)
$wuMail_Config->Host = 'smtp.gmail.com'; // Specify main and backup SMTP servers
$wuMail_Config->SMTPAuth = true; // Enable SMTP authentication (TRUE / FALSE)
$wuMail_Config->AuthType = 'LOGIN'; // Authentification type... ex: PLAIN, LOGIN
$wuMail_Config->Username = 'USERNAME#gmail.com'; // Only blank for GoDaddy's servers
$wuMail_Config->Password = 'PASSWORD'; // Only blank for GoDaddy's servers
$wuMail_Config->SMTPSecure = 'ssl'; // ('tls', 'ssl' or false)
$wuMail_Config->Port = 465; // TCP port to connect to
$wuMail_Config->Exceptions = true; // true/false, if Exceptions enabled
$wuMail_Config->SMTPDebug = 0; // Enable verbose debug output ~~ must be 0 in production environment
//MESSAGE CONFIG SETTINGS - YOU CAN CHANGE THESE:
$wuMail_Config->DefaultToAddress = 'to#email.com';
$wuMail_Config->DefaultToName = 'To Name';
$wuMail_Config->DefaultCC = false; // no default CC
$wuMail_Config->DefaultBCC = false; // no default BCC
$wuMail_Config->DefaultFromAddress = 'from#email.com';
$wuMail_Config->DefaultFromName = 'From Name';
$wuMail_Config->DefaultReplyAddress = 'replyaddress#email.com';
$wuMail_Config->DefaultReplyName = 'Reply Name';
$wuMail_Config->DefaultSubject = 'Default Subject';
# MESSAGE / HTML VERSION CONFIG SETTINGS - YOU CAN CHANGE THESE. BE CAREFUL:
$wuMail_Config->DefaultMessage = 'Default Message (Message Not Supplied)';
$wuMail_Config->ForceHTML = true; // (recommended: true)
// If set to TRUE, and no HTML version of message is supplied to wuMail function, use the HTML template below...Otherwise use HTML supplied to wuMail function if it is supplied.
// If set to FALSE, and no HTML version of message is supplied to wuMail function, simply display a non-HTML message to recipient. If HTML version is supplied, HTML version will be used instead of template
# DefaultHTML: Simply use {!messageInsert!} to insert the regular non-HTML message into the template. {!siteNameInsert!} will insert the config site name.
$wuMail_Config->DefaultHTML = '
<div>
<center><img style="width:350px; height:auto; margin-bottom:25px;" src="site.com/logo.png" alt="Site Name" /></center>
<div style="width:100%; color:white; background-color:#c02026; font-weight:500; padding:10px;">Important Information</div>
<div style="width:100%; padding:25px; color:black; background-color:#f2f2f2;">
{!messageInsert!}
</div>
</div>
';
# NOTE: The 'HTML' key in the options data array for wuMail can be a template with {!messageInsert!} or {!siteNameInsert!} as variables!
// PHPMailer Path Settings:
$wuMail_Path = ""; // path from root dir for site access
// DO NOT REMOVE:
require $wuMail_Path . "wuMail.php";
?>
The URL & logo image in the template should obviously be updated... This is the default template if someone supplies an email message without the HTML version. This is so every email can use HTML templates when allowed, even if developers don't properly use one in the first place :) System settings for the win!
Next we have wuMail.php itself...
<?php
/*
NOTE: These settings have been prepared by
WUBUR.COM / WUBUR LLC / BILLY LOWERY / WILL PASSMORE
*/
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require $wuMail_Path . 'src/Exception.php';
require $wuMail_Path . 'src/PHPMailer.php';
require $wuMail_Path . 'src/SMTP.php';
function wuMail($data, $multi = false){
global $wuMail_Config;
if(!is_array($data)){
$useDefaults = true;
} else {
$useDefaults = false;
}
$mailSettings = array(
"TOADDRESS" => $wuMail_Config->DefaultToAddress,
"TONAME" => $wuMail_Config->DefaultToName,
"CC" => $wuMail_Config->DefaultCC,
"BCC" => $wuMail_Config->DefaultBCC,
"SUBJECT" => $wuMail_Config->DefaultSubject,
"MESSAGE" => $wuMail_Config->DefaultMessage,
"HTML" => $wuMail_Config->DefaultHTML,
"FROMADDRESS" => $wuMail_Config->DefaultFromAddress,
"FROMNAME" => $wuMail_Config->DefaultFromName,
"REPLYADDRESS" => $wuMail_Config->DefaultReplyAddress,
"REPLYNAME" => $wuMail_Config->DefaultReplyName
);
# NOTES: THE FOLLOWING CAN BE ARRAYS: ToAddress, ToName (arr key must match ToAddress arr), CC, BCC
# IN FUTURE, YOU CAN LINE UP EMAILS TO SEND SEPARATELY BY SIMPLY MAKING MULTIDIMENSIONAL ARRAY OF DATA, AND SETTING PARAM 2 (MULTI) EQUAL TO TRUE IN WUMAIL
if($useDefaults !== true){
$submittedOpts = array();
foreach($data as $submittedOption => $submittedValue){
$submittedOptionUPPER = strtoupper($submittedOption);
$submittedOpts[] = $submittedOptionUPPER;
if(isset($mailSettings[$submittedOptionUPPER])){
$mailSettings[$submittedOptionUPPER] = $data[$submittedOption];
} else {
echo "ERROR: SUBMITTED MAIL OPTION NOT ACCEPTED";
}
}
if(($mailSettings['TOADDRESS'] !== $wuMail_Config->DefaultToAddress) && !in_array('TONAME', $submittedOpts)){ # To address supplied, but no to name supplied
# do not use a toName...
$mailSettings['TONAME'] = false;
}
if(($mailSettings['FROMADDRESS'] !== $wuMail_Config->DefaultFromAddress) && !in_array('FROMNAME', $submittedOpts)){ # From address supplied, but no fromname supplied
$mailSettings['FROMNAME'] = false;
# do not use fromname below, because the supplied from address differs from the default in settings
}
if(($mailSettings['REPLYADDRESS'] !== $wuMail_Config->DefaultFromAddress) && !in_array('REPLYNAME', $submittedOpts)){ # Reply address supplied, but no replyname supplied
$mailSettings['REPLYNAME'] = false;
# do not use replyname below, because the supplied reply address differs from the default in settings
}
} # useDefaults !== true
$mail = new PHPMailer($wuMail_Config->Exceptions);
try {
//Server Settings (from PHPMailer/config.php) - Change in config.php file, not here!
$mail->SMTPDebug = $wuMail_Config->SMTPDebug;
if($wuMail_Config->isSMTP === true){ $mail->isSMTP(); }
$mail->Host = $wuMail_Config->Host;
$mail->SMTPAuth = $wuMail_Config->SMTPAuth;
$mail->AuthType = $wuMail_Config->AuthType;
$mail->Username = $wuMail_Config->Username;
$mail->Password = $wuMail_Config->Password;
$mail->SMTPSecure = $wuMail_Config->SMTPSecure;
$mail->Port = $wuMail_Config->Port;
//Recipients
if($mailSettings['FROMNAME'] !== false){
$mail->setFrom($mailSettings['FROMADDRESS'], $mailSettings['FROMNAME']);
} else {
$mail->setFrom($mailSettings['FROMADDRESS']);
}
if($mailSettings['TONAME'] !== false){
$mail->addAddress($mailSettings['TOADDRESS'], $mailSettings['TONAME']);
} else {
$mail->addAddress($mailSettings['TOADDRESS']);
}
if($mailSettings['REPLYNAME'] !== false){
$mail->addReplyTo($mailSettings['REPLYADDRESS'], $mailSettings['REPLYNAME']);
} else {
$mail->addReplyTo($mailSettings['REPLYADDRESS']);
}
if($mailSettings['REPLYNAME'] !== false){
$mail->addReplyTo($mailSettings['REPLYADDRESS'], $mailSettings['REPLYNAME']);
} else {
$mail->addReplyTo($mailSettings['REPLYADDRESS']);
}
if($mailSettings['CC'] !== false){
$mail->addCC($mailSettings['CC']);
}
if($mailSettings['BCC'] !== false){
$mail->addCC($mailSettings['BCC']);
}
//Attachments
#$mail->addAttachment('/var/tmp/file.tar.gz'); // Add attachments
#$mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // Optional name
if($wuMail_Config->ForceHTML !== true && !in_array("HTML", $submittedOpts)){ # ForceHTML is not enforced, and HTML not submitted.... Use plain text message:
$mailSettings['HTML'] = $mailSettings['MESSAGE'];
$mail->isHTML(false);
} else if($wuMail_Config->ForceHTML === true && !in_array("HTML", $submittedOpts)){ # ForceHTML is true, and wuMail received no HTML template to use: ... use default:
$templateVarFind = array("{!messageInsert!}", "{!siteNameInsert!}");
$templateVars = array($mailSettings['MESSAGE'], $wuMail_Config->SiteName);
$mailSettings['HTML'] = str_replace($templateVarFind, $templateVars, $mailSettings['HTML']); // insert variables into default wuMail HTML template
$mail->isHTML(true);
} else {
$mail->isHTML(true);
}
$mail->Subject = $mailSettings['SUBJECT'];
if($mailSettings['HTML'] == $mailSettings['MESSAGE']){
$mail->Body = $mailSettings['MESSAGE'];
} else {
$mail->Body = $mailSettings['HTML'];
$mail->AltBody = $mailSettings['MESSAGE'];
}
$mail->send();
return true;
} catch (Exception $e) {
return 'Message could not be sent. Mailer Error: ' . $mail->ErrorInfo;
}
} // wuMail end
?>
Finally, after all of this is setup in config.php and wuMail.php, we can begin to use the wuMail() function
require_once "wuMail/config.php";
$mailData = array(
"TOADDRESS" => "userToSendTo#email.com",
"TONAME" => "First Name",
"SUBJECT" => "Registration",
"MESSAGE" => "Hello this is a message",
"HTML" => "Hello this is a <strong>message</strong>",
"FROMADDRESS" => "from#website.com",
"FROMNAME" => "Admin Mail",
"REPLYADDRESS" => "donotreply#email.com"
);
if(wuMail($mailData) === true){
// mail sent
} else {
// mail not successful, change SMTPDebug to = 4 in config.php to bug test
}
As you can see, not all parameters have to be supplied...In the $mailData array you can supply:
$mailSettings = array(
"TOADDRESS" => $wuMail_Config->DefaultToAddress,
"TONAME" => $wuMail_Config->DefaultToName,
"CC" => $wuMail_Config->DefaultCC,
"BCC" => $wuMail_Config->DefaultBCC,
"SUBJECT" => $wuMail_Config->DefaultSubject,
"MESSAGE" => $wuMail_Config->DefaultMessage,
"HTML" => $wuMail_Config->DefaultHTML,
"FROMADDRESS" => $wuMail_Config->DefaultFromAddress,
"FROMNAME" => $wuMail_Config->DefaultFromName,
"REPLYADDRESS" => $wuMail_Config->DefaultReplyAddress,
"REPLYNAME" => $wuMail_Config->DefaultReplyName
);
As you can see, there are quite a few custom parameters you can enter into wuMail($data) when you want to send mail. If you leave any out, it defaults to the settings in config.php for that specific setting! The reply address/name & to address/name & from name/address all are dynamic so that if you supply a custom address (but no name), it will not mismatch the custom email with the default name. It will simply send it with that information as blank.
You can download wuMail if you want it at:
http://nerdi.org/stackoverflow/wuMail.zip
wuMail comes with PHPMailer packaged in and is 100% free... obviously :)
In below code, we are first selecting users based on the admin's input from database. Then sending emails to those users. With the code it sends emails to $mail_news->addAddress('testuser#gmail.com'); test user. But for the bcc part is not working, as it doesn't send any emails to bcc email users.
foreach($email_array as $news_mail){
$mail_news->AddBCC($news_mail.";");
}
This is how we fetch user emails via form & PHP prepare statement with mysqli.
Here is the main part code:
if($msn->execute()){
$msn->store_result();
$msn->bind_result($news_mail);
while($msn->fetch()){
$email_array[] = $news_mail;
}
// echo "successful";
}
else
{
echo "database failed";
}
//--Email Sending Starts
$mail_news = new PHPMailer;
$mail_news->isSMTP();
$mail_news->Host = EMAIL_HOST;
$mail_news->SMTPAuth = true;
$mail_news->Port = EMAIL_PORT;
$mail_news->SMTPSecure = 'tls';
$mail_news->Username = EMAIL_ADD;
$mail_news->Password = EMAIL_PASS;
$mail_news->From = EMAIL_ADD;
$mail_news->FromName = 'Company Account';
$mail_news->addAddress('testuser#gmail.com');
foreach($email_array as $news_mail){
$mail_news->AddBCC($news_mail.";");
}
$mail_news->WordWrap = 50;
// $mail_news->SMTPDebug = 2;
$mail_news->isHTML(true);
$mail_news->Subject = "".$sub;
$mail_news->Body = "".$body;
$mail_news->AltBody = "".$altbody;
if(!$mail_news->send()) {
echo "Failed Sending Emails" ;
echo 'Mailer Error: ' . $mail_news->ErrorInfo;
} else {
echo "All Email sending completed" ;
}
?>
</form>
<?php
$msn->close(); // Finally closing the database
}
?>
You need to change the line
$mail_news->AddBCC($news_mail.";");
with
$mail_news->AddBCC($news_mail);
because the method addBCC() handles the semicolon by itself. You do not need to specify by your own.
The following program is intended to match incoming email aliases with those in the database, and forward the email to the right address, like Craigslist does.
I am now getting this error:
Error: [1] You must provide at least one recipient email address.
in anon-email.php at line number: sending the email
Here is the code:
$mailboxinfo = imap_mailboxmsginfo($connection);
$messageCount = $mailboxinfo->Nmsgs; //Number of emails in the inbox
for ($MID = 1; $MID <= $messageCount; $MID++)
{
$EmailHeaders = imap_headerinfo($connection, $MID); //Save all of the header information
$Body = imap_qprint(imap_fetchbody($connection, $MID, 1)); //The body of the email to be forwarded
$MessageSentToAllArray = $EmailHeaders->to; //Grab the “TO” header
$MessageSentToAllObject = $MessageSentToAllArray[0];
$MessageSentToMailbox = $MessageSentToAllObject->mailbox ."#". $MessageSentToAllObject->host; //Everything before and after the “#” of the recipient
$MessageSentFromAllArray = $EmailHeaders->from; //Grab the “FROM” header
$MessageSentFromAllObject = $MessageSentFromAllArray[0];
$MessageSentFromMailbox = $MessageSentFromAllObject->mailbox ."#". $MessageSentFromAllObject->host; //Everything before and after the “#” of the sender
$MessageSentFromName = $MessageSentFromAllObject->personal; //The name of the person who sent the email
$toArray = searchRecipient($MessageSentToMailbox); //Find the correct person to send the email to
if($toArray == FALSE) //If the alias they entered doesn’t exist…
{
$bounceback = 'Sorry the email in your message does not appear to be correct';
/* Send a bounceback email */
$mail = new PHPMailer(); // defaults to using php “mail()”
$mail -> ContentType = 'text/plain'; //Plain email
$mail -> IsHTML(false); //No HTML
$the_body = wordWrap($bounceback, 70); //Word wrap to 70 characters for formatting
$from_email_address = 'name#domain.com';
$mail->AddReplyTo($from_email_address, "domain.Com");
$mail->SetFrom($from_email_address, "domain.Com");
$address = $MessageSentFromMailbox; //Who we’re sending the email to
$mail->AddAddress($address, $MessageSentFromName);
$mail->Subject = 'Request'; //Subject of the email
$mail->Body = $the_body;
if(!$mail->Send()) //If the mail fails, send to customError
{
customError(1, $mail->ErrorInfo, "anon-email.php", "sending the email");
}
}
else //If the candidate address exists, forward on the email
{
$mail = new PHPMailer(); // defaults to using php “mail()”
$mail -> ContentType = 'text/plain'; //Plain E-mail
$mail -> IsHTML(FALSE); //No HTML
$the_body = wordwrap($Body, 70); //Wordwrap for proper email formatting
$from_email_address = "$MessageSentFromMailbox";
$mail->AddReplyTo($from_email_address);
$mail->SetFrom($from_email_address);
$address = $toArray[1]; //Who we’re sending the email to
$mail->AddAddress($address, $toArray[0]); //The name of the person we’re sending to
$mail->Subject = $EmailHeaders->subject; //Subject of the email
$mail->Body = ($the_body);
if(!$mail->Send()) //If mail fails, go to the custom error
{
customError(1, $mail->ErrorInfo, "anon-email.php", "sending the email");
}
}
/* Mark the email for deletion after processing */
imap_delete($connection, $MID);
}
imap_expunge($connection); // Expunge processes all of the emails marked to be deleted
imap_close($connection);
function searchRecipient() // function to search the database for the real email
{
global $MessageSentToMailbox; // bring in the alias email
$email_addr = mysql_query("SELECT email FROM tbl WHERE source='$MessageSentToMailbox'"); // temp store of the real email
$row = mysql_fetch_array($email_addr); //making temp store of data for use in program
if(empty($row['email']))
{
return FALSE;
}
else /* Else, return find the person's name and return both in an array */
{
$results = mysql_query("SELECT * FROM tbl WHERE email = '$email_addr'"); // temp store of both queries from this function
$row = mysql_fetch_array($results, $email_addr); //making temp store of data for use in program
$name = $row['author']; // taking the author data and naming its variable
return array($name, $email_addr); // this is the name and the real email address to be used in function call
}
}
function customError($errno, $errstr, $file, $line)
{
error_log("Error: [$errno] $errstr in $file at line number: $line",1, "name#domain.com","From: name#domain.com.com");
die();
}
Here is the first thing I would try:
It would appear that your function searchRecipient isn't being passed a parameter. Rather than use the global keyword, I would define it in your function call. Also, mysql_fetch_array does not pass back an associative array, which is what you are using in your next step. I would change that to mysql_fetch_assoc (it's the same thing essentially). There are also a few other minor syntax corrections in this function. Here are my proposed changes to that function. I think this should fix your problem. Or at least get you moving forward.
function searchRecipient($MessageSentToMailbox) // function to search the database for the real email
{
$email_addr = mysql_query("SELECT email FROM tbl WHERE source='$MessageSentToMailbox'"); // temp store of the real email
$row = mysql_fetch_assoc($email_addr); //making temp store of data for use in program
if(empty($row['email']))
{
return FALSE;
}
else /* Else, return find the person's name and return both in an array */
{
$email_addr = $row['email'];
$results = mysql_query("SELECT * FROM tbl WHERE email = '$email_addr'"); // temp store of both queries from this function
$row = mysql_fetch_assoc($results); //making temp store of data for use in program
$name = $row['author']; // taking the author data and naming its variable
return array($name, $email_addr); // this is the name and the real email address to be used in function call
}
}
You could also combine this into one query and make it a little easier. Here is that solution.
function searchRecipient($MessageSentToMailbox)
{
$results = mysql_query("SELECT email, author FROM tbl WHERE source='$MessageSentToMailbox'");
$row = mysql_fetch_assoc($results);
if(empty($row['email']) || empty($row['author'])) return false;
return array($row['email'], $row['author']);
}
I've written my own Code Igniter model for sending emails. All was fine until recently when I started to get this error:
Fatal error: Cannot redeclare class phpmailerException in /home/mysite/public_html/subdir/application/libraries/phpmailer/class.phpmailer.php on line 2319
I'm using:
CodeIgniter 2
PHPMailer 5.1
I've tried the following to resolve it:
Added "$mail->SMTPDebug = 0" to turn off errors.
Added: "$mail->MailerDebug = false;"
Modified the PHPMailer to only show errors when SMTPDebug is turned on.
Looked for and removed any echo statements
Added try / catch blocks Tried adding / removing: $mail = new PHPMailer(true);
Here is my controller method (company/contact) which calls my model (message_model):
function contact()
{
//Do settings.
$this->options->task='email';
$this->options->change = 'sent';
$this->options->form_validation='';
$this->options->page_title='Contact Us';
//Import library
include_once('application/libraries/recaptcha/recaptchalib.php');//Include recaptcha library.
//Keys for recaptcha, stored in mainconfig file.
$this->options->publickey = $this->config->item('recaptcha_public');
$this->options->privatekey = $this->config->item('recaptcha_private');
//Form validation
$this->form_validation->set_error_delimiters('<div class="error">', '</div>');
$this->form_validation->set_rules('name_field','Name of problem','trim|required|min_length[3]|max_length[100]');
$this->form_validation->set_rules('desc_field','Description','trim|required|min_length[10]|max_length[2000]');
$this->form_validation->set_rules('email_field','Your email address','trim|required|valid_email');
$this->form_validation->set_rules('recaptcha_response_field','captcha field','trim|required|callback__check_recaptcha');
//If valid.
if( $this->form_validation->run() )
{
//Set email contents.
$message="This is a message from the contact form on ".$this->config->item('site_name')."<br /><br />";
$message.=convert_nl($this->input->post('desc_field'));
$message.="<br /><br />Reply to this person by clicking this link: ".$this->input->post('name_field')."<br /><br />";
$options = array('host'=>$this->config->item('email_host'),//mail.fixilink.com
'username'=>$this->config->item('email_username'),
'password'=>$this->config->item('email_password'),
'from_name'=>$this->input->post('name_field'),
'to'=>array($this->config->item('email_to')=>$this->config->item('email_to') ),
'cc'=>$this->config->item('email_cc'),
'full_name'=>$this->input->post('name_field'),
'subject'=>'Email from '.$this->config->item('site_name').' visitor: '.$this->input->post('name_field'),
'message'=>$message,
'word_wrap'=>50,
'format'=>$this->config->item('email_format'),
'phpmailer_folder'=>$this->config->item('phpmailer_folder')
);
//Send email using own email class and phpmailer.
$result = $this->message_model->send_email($options);
//Second email to sender
//Set email contents.
$message="Thank you for your enquiry, we aim to get a reply to you within 2 working days. In the meantime, please do follow us on www.facebook.com/autismworksuk";
$options = array('host'=>$this->config->item('email_host'),//mail.fixilink.com
'username'=>$this->config->item('email_username'),
'password'=>$this->config->item('email_password'),
'from_name'=>$this->input->post('name_field'),
'to'=>$this->input->post('email_field'),
'full_name'=>$this->input->post('name_field'),
'subject'=>'Email from '.$this->config->item('site_name'),
'message'=>$message,
'word_wrap'=>50,
'format'=>$this->config->item('email_format'),
'phpmailer_folder'=>$this->config->item('phpmailer_folder')
);
//Send email using own email class and phpmailer.
$result = $this->message_model->send_email($options);
//Set result.
if($result==-1)
$this->session->set_flashdata('result', ucfirst($this->options->task).' was not '.$this->options->change.' because of a database error.');
elseif($result==0)
$this->session->set_flashdata('result', 'No changes were made.');
else
$this->session->set_flashdata('result', ucfirst($this->options->task).' was '.$this->options->change.' successfully.');
//Redirect to completed controller.
redirect('completed');
}
//Validation failed or first time through loop.
$this->load->view('company/contact_view.php',$this->options);
}
Here is my model's method to send the emails. It used to work but without any changes I can think of now I get an exception error:
function send_email($options=array())
{
if(!$this->_required(array('host','username','password','from_name','to','full_name','subject','message'),$options))//check the required options of email and pass aggainst provided $options.
return false;
$options = $this->_default(array('word_wrap'=>50,'format'=>'html','charset'=>'utf-8'),$options);
try
{
if(isset($options['phpmailer_folder']))
require($options['phpmailer_folder']."/class.phpmailer.php");
else
require("application/libraries/phpmailer/class.phpmailer.php");//Typical CI 2.1 folder.
$mail = new PHPMailer();
$mail->MailerDebug = false;
//Set main fields.
$mail->SetLanguage("en", 'phpmailer/language/');
$mail->IsSMTP();// set mailer to use SMTP
$mail->SMTPDebug = 0;
$mail->Host = $options['host'];
$mail->SMTPAuth = TRUE; // turn on SMTP authentication
$mail->Username = $options['username'];
$mail->Password = $options['password'];
$mail->FromName = $options['from_name'];//WHo is the email from.
$mail->WordWrap = $options['word_wrap'];// Set word wrap to 50 characters default.
$mail->Subject = $options['subject'];
$mail->Body = $options['message'];
$mail->CharSet = $options['charset'];
//From is the username on the server, not sender email.
if(isset($options['from']))
$mail->From = $options['from'];
else
$mail->From = $mail->Username; //Default From email same as smtp user
//Add reply to.
if(isset($options['reply_to']))
$mail->AddReplyTo($options['reply_to'], $options['from']);
if(isset($options['sender']))
$mail->Sender = $options['sender'];
//Add recipients / to field (required)
if(is_array($options['to']))
{
foreach($options['to'] as $to =>$fn)
$mail->AddAddress($to, $fn);
}
else
{
$mail->AddAddress($options['to']); //Email address where you wish to receive/collect those emails.
}
//Add cc to list if exists. Must be an array
if(isset($options['cc']))
{
if(is_array($options['cc']))
{
foreach($options['cc'] as $to =>$fn)
$mail->AddCC($to, $fn);
}
else
{
log_message('debug', '---->CC field must be an array for use with Message_Model.');
}
}
//Add bcc to list if exists. Must be an array
if(isset($options['bcc']))
{
if(is_array($options['bcc']))
{
foreach($options['bcc'] as $to =>$fn)
$mail->AddBCC($to, $fn);
}
else
{
log_message('debug', '---->BCC field must be an array for use with Message_Model.');
}
}
//Alternative text-only body.
if(isset($options['alt_body']))
$mail->AltBody=$options['alt_body'];
else
$mail->AltBody = htmlspecialchars_decode( strip_tags( $options['message'] ),ENT_QUOTES );//Strip out all html and other chars and convert to plain text.
//Plain/html format.
if(isset($options['format']))
{
if($options['format']=='html')
$mail->IsHTML(true); // set email format to HTML
}
//Send email and set result.
$return['message']='';
if(!$mail->Send())
{
$return['message'].= "Message could not be sent.<br />\n";
$return['message'].= "Mailer Error: " . $mail->ErrorInfo."\n";
$return['result'] = 0;
}
else
{
$return['message'].= "Message has been sent successfully.\n";
$return['result'] = 1;
}
}
catch (phpmailerException $e)
{
log_message('error', '---->PHPMailer error: '.$e->errorMessage() );
}
catch (Exception $e)
{
log_message('error', '---->PHPMailer error: '.$e->errorMessage() );
}
return $return;
}
if (!class_exists("phpmailer")) {
require_once('PHPMailer_5.2.2/class.phpmailer.php');
}
This Code will clear this issue 100%..
Basically one of two things is happening:
You are "including" your PHP code twice somewhere, causing the 2nd time to generate the redeclaration error
You are using "phpmailerException" somewhere else, besides your model. Have you tried to do a "find all" in your IDE for ALL calls to "phpmailerException" - perhaps you used this name in another area for another exception?
require_once("class.phpmailer.php") is better.
Mukesh is right that require_once will solve Sift Exchanges answer #1. However, there is not need to check if the class exists as require_once does that.