I am using a PHP Script written by me with AWS (Amazon Web Service) PHP Script to send emails using SMTP
Everytime I run this script, say I have 3 user's in my database, then the first user get's mail of the first, second and third person. The second user get's mail to second and third person. And the third user get's the mail to the third person only.
I don't know why this is happening, and been pulling my hair for some time. Maybe I am missing some point, that is why adding a question here.
Pre-Requisites:
func1() = Is used to get emails from DB whom I have not send Emails Yet, return's a single value (ID) only
func2() = Is used to get the data of that particular user whose ID was found in func1()
func3() = Is used to mark "Send" to that particular ID whom we send the mail.
<?php
require 'aws-autoloader.php';
require 'vendor/autoload.php';
$mail = new PHPMailer;
$mail->isSMTP();
$mail->setFrom('myemail#address.com', 'My Company Name');
$mail->Username = 'Username';
$mail->Password = 'Password';
$mail->Host = 'email-smtp.us-west-2.amazonaws.com';
class Db {
public function dbconnect(){
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "database";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
return $conn;
}
public function func1()
{
$conn=$this->dbconnect();
$stmt = $conn->prepare("CALL func1()");
$stmt->execute();
$result=NULL;
$result = $stmt->get_result();
$item=NULL;
while ($row = $result->fetch_array(MYSQLI_NUM))
{
$item[] = $row;
}
return $item;
$stmt->close();
$conn->close();
}
public function func2($id)
{
$conn=$this->dbconnect();
$stmt = $conn->prepare("CALL func2(?)");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
$item=NULL;
while ($row = $result->fetch_array(MYSQLI_NUM))
{
$item[] = $row;
}
return $item;
$stmt->close();
$conn->close();
}
public function func3($id)
{
$conn=$this->dbconnect();
$stmt = $conn->prepare("CALL func3(?)");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
$item=NULL;
while ($row = $result->fetch_array(MYSQLI_NUM))
{
$item[] = $row;
}
return $item;
$stmt->close();
$conn->close();
}
}
$count=0;
$obj=new Db;
$ids=$obj->func1();
while(($ids[0][0]!=0)&&($count<1000)){
$ids=$obj->func1();
$rslt=$obj->func2($ids[0][0]);
if($rslt[0][0]!=NULL)
{
$idno=$rslt[0][0];
$companyname=$rslt[0][2];
$email=$rslt[0][16];
$complete=NULL;
do{
$mail->addAddress($email, $companyname);
$mail->Subject = 'My Subject';
$mail->Body = '<p>Hello</p>';
$mail->AltBody = "Hello";
$mail->SMTPAuth = true;
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
$mail->isHTML(true);
if(!$mail->send()) {
echo "Email not sent. " , $mail->ErrorInfo , PHP_EOL;
} else {
$complete=$obj->func3($ids[0][0]);
}
}while($complete[0][0]!=3);
}
$count=$count+1;
//if($count%10==0) Trying to give a small break after each 10 emails are send
sleep(1);
}
$count=$count-1;
echo 'Email Send to: '.$count.' Users.<br>';
?>
After the function is called, I receive emails as described at the start. And all the users are marked "Send"
Any Idea what I may be doing wrong to get result like that.
Your code is using the same PHPMailer object for each email, and it is adding addresses using $mail->addAddress() without resetting the list of email addresses between emails hence the list of recipients is growing each time.
You can call $mail->clearAllRecipients() for each new email or you could create a new PHPMailer object for each email. Note that if you choose the former approach then you should check to see if there are any other things that also need to be reset from one email to the next.
Related
The assignment I'm working on (an E-commerce course) asks that I use php to generate a new password for a user and send the user an email with the new password. I successfully generate the password, send the email from my school's server to myself (a gmail account), using php mail() however the php variable representing the password is always blank. I have been looking for answers to this on here and other websites but cannot find what I'm doing wrong.
I am looking to solve this particular issue and am not looking to use PHPMailer or some other alternative. Also I am not looking to discuss more secure ways to send email, or discuss encryption, just looking to discuss this particular issue and why it is or isn't working. Thank you in advance for any advice.
if ($mysqli->conect_errno) {
die("Error: Could not connect to database." . $mysqli->connect_error);
} else {
echo "<p>Connected<br></p>";
}
$email = $_POST['email_input'];
try {
$password = reset_password($email, $mysqli);
notify_password($email, $password, $mysqli);
echo 'Your password has changed and has been emailed to you.<br>';
}
catch(Exception $e) {
echo 'Your password could not be reset';
}
function reset_password($email, $mysqli){
$new_password = randomString(8, 12);
if ($new_password == false) {
throw new Exception('could not generate new password');
}
$rand_number = rand(0, 999);
$new_password .= $rand_number;
echo "NEW PASSWORD: " .$new_password."\r\n";
$query = "UPDATE registration
SET password = sha1('".$new_password."')
WHERE email = '".$email."'";
$result = $mysqli->query($query);
if($result) {
echo "<br>Password Reset<br>";
}else {
echo "An error has occured";
}
}
function randomString($min_length, $max_length){
return substr(str_shuffle("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), $min_length, $max_length);
}
function notify_password($email, $password, $mysqli){
$query = "SELECT email FROM registration WHERE email='".$email."'";
$result = $mysqli->query($query);
if(!$result){
throw new Exception('could not find email address');
}else if ($result->num_rows == 0) {
throw new Exception('Could not find email address:user not in database');
}else {
$row = $result->fetch_object();
$email = $row->email;
$from = "From support#HelpFinder \r\n";
$mesg = "Your password has been changed to ".$password."\r\n"."Please change it the next time you log in.\r\n";
if(mail($email, 'HelpFinder Login Information', $mesg, $from)) {
return true;
}else {
throw new Exception('Could not send email.');
}
}
}
the email message that arrives
example from text book I'm learning from
check if you are sending the $password variable as parameter correctly,
may be its empty
First please check that you have a double $result before the if declaration.
$result = $result = $mysqli->query($query);
After that you could try to make a var_dump to $password variable to check if it was correctly passed to the notify_password function. You could also post the $password variable definition so we could check in more depth.
I am trying to make a user registration script.
In my registration.php script, I validate user inputs then insert them into database. I then want to send the user a verification link in an email using SMTP with:
$user_activation_hash = sha1(uniqid(mt_rand(), true)); //creating ramdom string
$mail = new PHPMailer;
$mail->IsSMTP();
$mail->CharSet = 'UTF-8';
$mail->Host = "info"; // SMTP server
$mail->Username = "info"; // SMTP account username
$mail->Password = "info"; // SMTP account password
$mail->SMTPAuth = true; // enable SMTP authentication
$mail->Port = info; // set the SMTP port for the server
$mail->From = "info"; //the email the mail comes from
$mail->FromName = "someName"; //what name should be shown at the email
$mail->AddAddress($email); //where the mail should be sent to
$mail->Subject = "email validation"; //subject of the mail
//how the link should look in the mail the "url" should point to the verification.php file
$link = "url path to my verification.php script".'?verification_code='.urlencode($user_activation_hash);
//the message in the mail with the above link
$mail->Body = "Please click on this link to activate your account:".' '.$link;
if(!$mail->Send()) {
echo "there was an error sending the mail" . ' ' . $mail->ErrorInfo;
//if there is an error sending the mail then I delete it here
return false;
} else {
//here I update the user with the new random created string
$sql = 'UPDATE `user` SET verification = :verification WHERE Id = :Id';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':Id', $Id, PDO::PARAM_STR);
$stmt->bindParam(':verification', $user_activation_hash, PDO::PARAM_STR);
$stmt->execute();
$dbh = null;
return true;
}
All of this works fine so far the registered user gets an email with the random link created.
here is an example of the link the user gets: http://url/to/verification.php?verification_code=80371b8ff9b0d5fb444f4be68c8b5a0d9757603b
When they click the link they are directed to my verification.php script:
if(!empty($_GET['verification_code']) && isset($_GET['verification_code'])){
$verificationCode = $_GET['verification_code'];
//check the database for the verification code from the link
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification AND isActive = 0';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':verification', $verificationCode, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
$Id = $row['Id'];
if (empty($row)){
echo "the account was not found";
}else{
//if they match. make the user active in db
$sql = 'UPDATE user SET isActive = 1, verification = NULL WHERE Id=:Id';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':Id', $Id, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
echo "The account has been activated!";
}
}
}
Okay so here is my headache and I hope I can explain it properly:
All of this works. When I create the first user it works after registration I can see a verification code in the database and when I click the link it gets activated. But the following users getting registered is being activated at once when I hit the registration.php script! It is like both scripts are being run at once and then making the activation link completely unnecessary.
I have no idea what causes this behavior. Is it because my pdo connection isn't closed properly from my first script? Is it because PHP normally just runs all scripts in a directory when only one I called? Is it because I don't understand how the $_GET function works?
I can't possible find a way why this shouldn't work so here is some of the things I have already tried:
I have tried registering a user with the verification.php script commented out then first uncomment it and click the link being send when the user is registered. this works.
I have tried moving my verification.php script to another folder. Didn't help anything
I have tried closing the connection in the verification.php then made a new PDO after. this didn't work either.
I have tried alot of ways to change the $_GET method but no success.
UPDATE!: now i have tried to see exactly where the code breaks and i noticed something unusual. when the registration.php is run the user is set in the database as not active. As soon as i recieve the email with the link. the user is set to active, without ever clicking the link
Please tell me someone out there knows what's up.
the problem is the first user when registered the table was completely empty
but when the second user registered and enter the verification.php with no get value it searches for the user that has verification = null (the first user)
and complete the code esily so all you need is to modify your code
just edit the first query in the verification.php file instead of this
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification';
do it like this
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification AND isActive = 0';
for the checking that if the value is sent or not
if(isset($_GET["verification_code"]){
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification AND isActive = 0';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':verification', $verificationCode, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
$Id = $row['Id'];
if ($Id == null){
echo "the account was not found";
}else{
// check if the verificationcode found in the database, matches the verificationcode from the link
if ($row['verification'] !== $verificationCode) {
//checking if it already exists and if there is an error then deleting the user
} else {
//if they match. make the user active in db
$sql = 'UPDATE user SET isActive = 1, verification = NULL WHERE Id=:Id';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':Id', $Id, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
echo "The account has been activated!";
}
}
}
So a couple of months ago i worked on my registration form with an com code (that is being send through the email) to activate it. The case is that the registration, and the activation of it always worked. But since recently, after some changes, it suddenly wont work anymore. The registration works,the email is being send to me with the com code link, and it also says i can now log in, but as soon as i try to log in with the made account, it sends me to my login error (wrong password or email). As soon as i look in my databse i also see that the data hasnt been inserted (its empty). Ive looked and done multiple things trying to get it fixed but none of it is working. So my last resort: stack;) The code is posted below (left the form code out btw since i dont think that is giving the problem):
The code for connection to the databse is (which is included everywhere):
<?php
$user = "XX";
$host = "XX";
$password = "XX"; //http://www.codinghorror.com/blog/2007/09/youre-probably-storing-passwords-incorrectly.html //
$database = "XX";
$conn = new mysqli($host, $user, $password, $database)or die ("Error message");
// check connection
if ($conn->connect_error) {
trigger_error('Database connection failed: ' . $conn->connect_error, E_USER_ERROR);
}
?>
After entering the register button this is the register checking page:
session_start();
include('configdb.php');
if(isset($_SESSION['error']))
{
header("Location: indexresp.php");
exit;
}
else{
if (isset($_POST["submit"])){
$register = $_POST['submit'];
$email2 = strip_tags($_POST['email']);
mysqli_select_db($conn, $database);
$emailcheck = mysqli_query($conn, "SELECT email from user WHERE email='$email2'");
$check = mysqli_num_rows($emailcheck);
if ($check == 0){
}
else {
$_SESSION['error']['email'] = "This Email is already used.";
header("Location: indexresp.php");
exit;
}
}
// the register (form field) data:
$voornaam = $_POST['voornaam'];
$achternaam = $_POST['achternaam'];
$email = $_POST['email'];
$password = $_POST['wachtwoord'];
$com_code = md5(uniqid(rand()));
$sql2 = "INSERT INTO user (email, password, com_code, voornaam, achternaam) VALUES ('$email', '$password', '$com_code', '$voornaam', '$achternaam')";
require("class.phpmailer.php");
$mail = new PHPMailer();
$mail->CharSet = 'UTF-8';
$mail->IsSMTP(); // set mailer to use SMTP
$mail->SMTPSecure = "tls";
$mail->Host = "smtp.gmail.com"; // specify main and backup server
$mail->SMTPAuth = true; // turn on SMTP authentication
$mail->Port = XXX;
$mail->Username = "XXXXX"; // SMTP username
$mail->Password = "XXX"; // SMTP password
$mail->SetLanguage("nl");
$mail->From = "XXXXX";
$mail->FromName = "Oblectare";
$mail->AddAddress("$email");
// name is optional
$mail->AddReplyTo("XXXXX", "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 = "Account registratie";
$mail->Body = "http://localhost/debasis/hoofdstuk03/confirm.php?passkey=$com_code <br>This adress needs to be copyed in the browser and this is your password:<br><br>" .$password;
$mail->AltBody = "http://localhost/debasis/hoofdstuk03/confirm.php?passkey=$com_code. This adress needs to be copyed in the browser and this is your password:" .$password;
if(!$mail->Send())
{
echo "Error mail<p>";
echo "Mail Error: " . $mail->ErrorInfo;
exit;
}
include ('mailconfirmation.php'); // text to say the email has been send
}
So this code sends an email with the activation code (com code). The code for the email confirmation is just plain text so i left it out.
The next being done is setting the activation (with the supplied link) to yes. This is the code that does that:
include('configdb.php');
$passkey = $_GET['passkey'];
$sql = "UPDATE user SET com_code=NULL WHERE com_code='$passkey'";
$result = mysqli_query($conn,$sql) or die(mysqli_error());
if($result)
{
echo '<div>Your account is now active. You may now Log in</div>';
}
else
{
echo "Some error occur.";
}
?>
So when it passes the if (connection) the user gets redirected to the index where he can login with his account info and his info should be activated (by the update). I think the problem is in this piece of code as the sql variable in here doesnt update the com_code anymore for some reason.
After the redirection i try to login with the just inputted (and as it should be: the activated) details.
The code that checks the login (which look if the pass and mail are valid) is as follows:
session_start();
include('configdb.php');
if(isset($_POST['submit_login']))
{
$email = trim($_POST['email']);
$password = trim($_POST['password']);
$result = mysqli_query($conn,"SELECT * FROM user WHERE email='$email' AND password='$password' AND com_code IS NULL"); // was password
$num_row = mysqli_num_rows($result);
$row=mysqli_fetch_array($result);
if( $num_row ==1 )
{
$_SESSION['email']=$row['email'];
header("Location: member.php");
exit;
}
else
{
include ('errorlogin.php');
}
}
I hope one of you guys can help me with this problem cause after 2 hours searching it is (for now) enough for me;)
Sorry for my english and some dutch words in the code (try'd to translate some).
Thx in advance!
Your insert part :
$sql2 = "INSERT INTO user ..."
Is never used in the provided code. Maybe you removed the SQL process by error.
I have this method to notify "my followers" which is called after a new event has been added. It works but with more than one email makes all the process very slow since the popup waits that all the emails have been sent before showing to the user that the event has been added and the spinning wheel is going forever. I can't think of any way to do it "behind the scene" after the user get the message that the event has been added.
public function notifiedFollowers($creator_id, $type, $event_id){
$query = $this->_db->prepare("SELECT * FROM followers WHERE user_id = ?");
$query->bindParam(1, $creator_id, PDO::PARAM_INT);
$query->execute();
while($row = $query->fetch(PDO::FETCH_OBJ)) {
$creator = new User($creator_id);
$creatorName = $creator->data()->name;
$user = new User($row->followers_id);
$mail = new PHPMailer();
$template = New MailFactory();
$mail->IsSMTP();
$mail->Host = "myHost";
$mail->SMTPAuth = true;
$mail->Username = "myUser";
$mail->Password = "myPassword";
$mail->IsHTML(true);
$mail->From = 'from email';
$mail->FromName = 'from name';
$mail->AddAddress($user->data()->username);
$mail->Subject = 'add subject here';
$mail->Body = $template->notifiedFollowersEmail($creatorName, $user->data()->name, $type, $event_id);
if(!$mail->send()) {
echo $mail->ErrorInfo;
die();
}
}
}
*UPDATE******
I solved the problem using cron jobs. Please check my answer.
I finally found a perfect solution: Cron Job
First of all I created a database where I store the "job" that has to be done
CREATE TABLE IF NOT EXISTS `cron_jobs_new_event` (
`cron_job_id` int(32) NOT NULL AUTO_INCREMENT,
`event_id` int(32) NOT NULL,
`user_id` int(32) NOT NULL,
`notify` int(32) NOT NULL,
`executed` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`cron_job_id`),
KEY `event_id` (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Constraints for table `cron_jobs_new_event`
--
ALTER TABLE `cron_jobs_new_event`
ADD CONSTRAINT `cron_jobs_new_fk` FOREIGN KEY (`event_id`) REFERENCES `event` (`event_id`) ON DELETE CASCADE ON UPDATE CASCADE;
I use hostgator so I set up the cron job to run every 15 minutes:
cron.php simply call a method from my class Notification
<?php require 'core/init.php';
$notification = new Notification();
$notification->notifiedFollowers();
and this is my method that does the magic (at least for me ;-)
public function notifiedFollowers(){
$query = $this->_db->prepare("SELECT user_id FROM cron_jobs_new_event WHERE executed = '0' AND notify = '1'");
$query->execute();
while($row = $query->fetch(PDO::FETCH_OBJ)) {
$userCreator = $row->user_id;
$q = $this->_db->prepare("SELECT * FROM followers WHERE user_id = ?");
$q->bindParam(1, $userCreator, PDO::PARAM_INT);
$q->execute();
while($followers = $q->fetch(PDO::FETCH_OBJ)) {
$type='try';
$creator = new User($followers->user_id);
$creatorName = $creator->data()->name;
$userFollower = new User($followers->followers_id);
$mail = new PHPMailer();
$template = New MailFactory();
$mail->IsSMTP();
$mail->Host = "my host";
$mail->SMTPAuth = true;
$mail->Username = "my username";
$mail->Password = "myPassword";
$mail->IsHTML(true);
$mail->From = 'ev';
$mail->FromName = 'Events Team';
$mail->AddAddress($userFollower->data()->username);
$mail->Subject = 'Somebody add a new event!';
$mail->Body = $template->notifiedFollowersEmail($creatorName, $userFollower->data()->name, $type, $followers->event_id);
if(!$mail->send()) {
echo $mail->ErrorInfo;
die();
}
}
//here I update the database so next time the cron runs, It won't send the same message
$update = $this->_db->prepare("UPDATE cron_jobs_new_event SET executed = '1' WHERE cron_job_id = ?");
$update->bindParam(1, $row->cron_job_id, PDO::PARAM_INT);
$update->execute();
}
}
I hope this helps somebody else
You are looking for Threads
<?php
class AsyncEmail extends Thread {
public function __construct($arg){
$this->arg = $arg;
}
public function run() {
/** Add your email sending code here. **/
}
}
// and call this following lines in loop
$aEmail = new AsyncEmail( $arg );
var_dump($aEmail->start());
?>
This code will work asynchronously in the background of your code, and your user will not have to wait for any step to complete.
Have a look at this PHP threading call to a php function asynchronously
I am a bit confused about how to use foreach. I read some internet things on it and I kind of understand how it works, but I don't fully understand it. I think I could use foreach to create a PHP mass emailer that sends blank carbon copy to email addresses and adresses the customer by name in the subject (Dear, Michael Here is your email). I've figured out how to retrieve the names and emails from my database into variables and I know how to email, but I don't know how to send multiple emails at once and to associate the name and email address.
<?php
//Variables for connecting to your database.
//These variable values come from your hosting account.
$hostname = "MichaelBerna.db.10339998.hostedresource.com";
$username = "MichaelBerna";
$dbname = "MichaelBerna";
//These variable values need to be changed by you before deploying
$password = "********";
$usertable = "subscribers";
$yourfield = "name";
$yourfield1 = "email";
//Connecting to your database
$link = mysql_connect($hostname, $username, $password) OR DIE ("Unable to connect to database! Please try again later.");
mysql_select_db($dbname);
//Fetching from your database table.
$query = "SELECT * FROM $usertable";
$result = mysql_query($query);
if ($result)
{
while($row = mysql_fetch_array($result))
{
$name = $row["$yourfield"];
$email = $row["$yourfield1"];
echo "Name: $name<br>";
echo "Email: $email<br>";
//mysqli_free_result($result);
//mysqli_close($link);
}
}
?>
Here is my email code:
<?php
require_once '../PHPMailer_5.2.2/class.phpmailer.php';
$name = $_POST['name'] ;
$email = $_POST['email'] ;
//$file = $_POST['file'] ; // I'm going to later add a file later to be attached in email from database
$body = "Hey $name thank you for continuing to be a valued customer! This month's story is included in this email asa an attachment.";
$mail = new PHPMailer(true); //defaults to using php "mail()"; the true param means it will throw exceptions on errors, which we need to catch
try
{
$mail->AddAddress($email, $name);
$mail->SetFrom('admins_email#yahoo.com', 'Site Admin');
$mail->AddReplyTo('admins_email#yahoo.com', 'Site Admin');
$mail->Subject = "Dear $name Your monthly subscription has arrived!";
$mail->Body = $body;
if ($_FILES['file']['size'])
{
$mail->AddAttachment($_FILES['file']['tmp_name'], $_FILES['file']['name']);// attachment
}
$mail->Send();
echo "Email Sent Successfully</p>\n";
}
catch (phpmailerException $e)
{
echo $e->errorMessage(); //Pretty error messages from PHPMailer
}
catch (Exception $e)
{
echo $e->getMessage(); //Boring error messages from anything else!
}
?>
Basically, I need a way to combine these two scripts and link them together and that's what I'm unsure of how to do.
Put the mailing code in a function, e.g. send_mail(), so that it can be called from different places. Then change your database query loop to:
while ($row = mysql_fetch_assoc($result)) {
send_mail($row['name'], $row['email'), "Text of the email");
}