Send Multiple emails with PHPMailer within while loop

Viewed 527

I am trying to send multiple emails within while loop, With the following code its not sending email notification and giving error 'Fatal error: Uncaught Error: Class "PHPMailer" not found in C:\xampp\htdocs\clinic\paients\run_medications.php:98 Stack trace: #0 {main} thrown in'. While the location is correct and its sending single email from another child directory.

require_once('../includes/PHPMailer.php');
require_once('../includes/SMTP.php');
require_once('../includes/Exception.php');
$full_dt = date('Y-m-d H:i:s');
$dt = date('Y-m-d');
$dt_hr = date('H');
$check_timing = $con->prepare("SELECT medication, start_time, end_time FROM timings WHERE HOUR(end_time) = :end ");
$check_timing->bindparam(':end', $dt_hr);
$check_timing->execute();
$count1 = $check_timing->rowCount();
if($count1 > 0) {
while($rows = $check_timing->fetch(PDO:: FETCH_OBJ)) {
  $medication = $rows->medication;
  $start_time = $dt.' '. $rows->start_time;
  $end_time = $dt.' '.$rows->end_time;
  $timestamp = strtotime($end_time) + 60*60;
  $end_hour = date('Y-m-d H:i:s', $timestamp);
    $query = "SELECT a.location_code, b.* FROM patients a INNER JOIN medication b ON a.id = b.pat_id WHERE b.status != 2 AND b.directions = :med AND b.last_time NOT BETWEEN :start AND :end AND :crntime BETWEEN b.start_date AND b.end_date AND :crntime BETWEEN :end AND :end_hour";
    $statement = $con->prepare($query);
    $statement->bindparam(':med', $medication);
    $statement->bindparam(':start', $start_time);
    $statement->bindparam(':end', $end_time);
    $statement->bindparam(':crntime', $full_dt);
    $statement->bindparam(':end_hour', $end_hour);
    $statement->execute();
    $count = $statement->rowCount();
    if($count > 0) {
    while($row = $statement->fetch(PDO:: FETCH_OBJ)) {
            $drug_id = $row->drgid;
            $code = $row->location_code;
            $pat_id = $row->pat_id;
            $drug = $row->med_type.' - '.$row->drug.' ('.$row->strength.')';
            $dose = $row->dosage;
            $route = $row->route;
            $directions = $row->directions;
        
            $getUserName = "SELECT name FROM users WHERE FIND_IN_SET(location_code, :codes)>0 ";
            $runUser = $con->prepare($getUserName);
            $runUser->bindParam(':codes',$code);
            $runUser->execute();
            $check = $runUser->rowCount();
            if($check > 0) {
            $userRow = $runUser->fetch(PDO::FETCH_OBJ);
            $by = $userRow->name;
            }
        
            $insert_report = $con->prepare("
                INSERT INTO  `report` (`med_id`,`pat_id`,`dtime`,`responsible`,`status`) values(:m_id,:p_id,:time,:by,'3')");
            
                $insert_report->bindparam(':m_id',$drug_id);
                $insert_report->bindparam(':p_id',$pat_id);
                $insert_report->bindparam(':time',$end_time);
                $insert_report->bindparam(':by',$by);
                $insert_report->execute();
        
                $mail = new PHPMailer();
                $mail->isSMTP();
                $mail-> SMTPOptions = array (
                'ssl' => array (
                'verify_peer' => false,
                'verify_peer_name' => false,
                'allow_self_signed' => true
                )
                );
                $mail->Host = "smtp.gmail.com";
                $mail->SMTPAuth = true;
                $mail->SMTPSecure = "tls";
                $mail->Port = "587";
                $mail->Username = "from@gmail.com";
                $mail->Password = "12345678";
                $mail->Subject = "Medication Report";
                $mail->setFrom("from@gmail.com",$by);
                $mail->isHTML(true);
                //Attachment
                    //$mail->addAttachment('img/attachment.png');
                //Email body
                $mail->Body = "<h3>Medication Report by ($by) </h3></br>
                                You are being alerted that <b>$name</b> has missed their $directions Medication $row->med_type. And you may need to take appropriate action..";
                $mail->addAddress($to_email['Email_add']);
                $mail->send();

      } // /while 

    }// if num_rows
  }//while close
}// if num_rows
3 Answers

Where is your PHPMailerAutoload.php file located?

You need import it with this :

require_once('phpmailer/PHPMailerAutoload.php');

overall you must do this steps:

  • Download the package from https://github.com/PHPMailer/PHPMailer by clicking on the "Download ZIP" button on the far lower right of the page.

  • Unzip file.

  • upload the language folder, class.phpmailer.php, class.pop3.php, class.smtp.php, and PHPMailerAutoload.php all into the same directory on your server, I like to create a directory on the server called phpmailer to place all of these into.

  • load the class in your project:

    require_once('phpmailer/PHPMailerAutoload.php');

Done...

if you're not using exceptions, you do still need to load the Exception class as it is used internally.

So, put use at the top of your page like this (I think this is the reason why you're getting undefined error):

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

Then call files like this :

require 'path/to/PHPMailer/src/Exception.php';
require 'path/to/PHPMailer/src/PHPMailer.php';
require 'path/to/PHPMailer/src/SMTP.php';
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
try {
  $mail->SMTPDebug = 0;
  $mail->isSMTP();
  $mail->Host = "smtp.gmail.com";
  $mail->SMTPAuth = true;
  $mail->Username = "email@gmail.com";
  $mail->Password = "password";
  $mail->Port = 587;
  $mail->setFrom('admin@example.com', 'Mailer');
  $mail->addAddress($email);
  $mail->addReplyTo("user@gmail.com", "Alias");
  $mail->CharSet = "UTF-8";
  $mail->isHTML(true);
  $mail->Subject = $subject;
  $mail->Body = $message;
  $mail->send();
     echo "Mail sent.";
  } catch (Exception $e) {
     echo "Failed. Mailer error: {$mail->ErrorInfo}";
  }

Some times this line use PHPMailer\PHPMailer\PHPMailer; works like this use PHPMailer\PHPMailer; try both ways. but first one will work for you I think.

I dont use ssl options, if you need it just place it under isSMTP.

$mail-> SMTPOptions = array (
  'ssl' => array (
  'verify_peer' => false,
  'verify_peer_name' => false,
  'allow_self_signed' => true
  )
);

Here is the example for sending multiple emails : Send multiple email

Note: You have to set your gmail account to less secure for apps to use phpmailer.

Because Gmail has started imposing an authentication mechanism that substitutes SMTP athentication for OAuth2-based authorisation. more info

Less secure accounts more info , Less secure accounts

Google is blocking low secure accounts, to your knowledge.

You have in your code:

            $check = $runUser->rowCount();
            if($check > 0) {
            $userRow = $runUser->fetch(PDO::FETCH_OBJ);
            $by = $userRow->name;
            }
        
            $insert_report = $con->prepare("
                INSERT INTO  `report` (`med_id`,`pat_id`,`dtime`,`responsible`,`status`) values(:m_id,:p_id,:time,:by,'3')");
            
                $insert_report->bindparam(':m_id',$drug_id);
                $insert_report->bindparam(':p_id',$pat_id);
                $insert_report->bindparam(':time',$end_time);
                $insert_report->bindparam(':by',$by);

But if no rows are returned and $check is therefore 0, variable $by will not have been set. But you then continue with your logic to use $by for database insertion and for sending an email. I would think that this could possibly generate a database exception if column responsible is not nullable. In any case, this is clearly incorrect logic.

You also have lots of tests for the number of rows returned before you execute your while loops. These tests are really redundant: If the count of rows returned is 0, the while loop will exit immediately if you just test for the fetch statement returning FALSE. So the level of nesting can be reduced by removing those redundant checks.

The second problem is that your are reading column name from table users and storing it in varible $by. Yet the body of your email message references variuable $name, which has not been defined. I have tentatively replaced this with varibale $by. But only you can say whether that is correct or not. But clearly if not, then you need to initialize $name with its appropriate value.

$full_dt = date('Y-m-d H:i:s');
$dt = date('Y-m-d');
$dt_hr = date('H');
$check_timing = $con->prepare("SELECT medication, start_time, end_time FROM timings WHERE HOUR(end_time) = :end ");
$check_timing->bindparam(':end', $dt_hr);
$check_timing->execute();
while(($timingRow = $check_timing->fetch(PDO:: FETCH_OBJ)) !== FALSE) {
    $medication = $timingRow->medication;
    $start_time = $dt.' '. $timingRow->start_time;
    $end_time = $dt.' '.$timingRow->end_time;
    $timestamp = strtotime($end_time) + 60*60;
    $end_hour = date('Y-m-d H:i:s', $timestamp);
    $query = "SELECT a.location_code, b.* FROM patients a INNER JOIN medication b ON a.id = b.pat_id
             WHERE b.status != 2 AND b.directions = :med AND b.last_time NOT BETWEEN :start AND :end
             AND :crntime BETWEEN b.start_date AND b.end_date AND :crntime BETWEEN :end AND :end_hour";
    $statement = $con->prepare($query);
    $statement->bindparam(':med', $medication);
    $statement->bindparam(':start', $start_time);
    $statement->bindparam(':end', $end_time);
    $statement->bindparam(':crntime', $full_dt);
    $statement->bindparam(':end_hour', $end_hour);
    $statement->execute();
    while(($row = $statement->fetch(PDO:: FETCH_OBJ)) !== FALSE) {
        $drug_id = $row->drgid;
        $code = $row->location_code;
        $pat_id = $row->pat_id;
        $drug = $row->med_type.' - '.$row->drug.' ('.$row->strength.')';
        $dose = $row->dosage;
        $route = $row->route;
        $directions = $row->directions;
    
        $getUserName = "SELECT name FROM users WHERE FIND_IN_SET(location_code, :codes)>0 ";
        $runUser = $con->prepare($getUserName);
        $runUser->bindParam(':codes',$code);
        $runUser->execute();
        $userRow = $runUser->fetch(PDO::FETCH_OBJ);
        if ($userRow !== FALSE) {
            $by = $userRow->name;
    
            $insert_report = $con->prepare("
                INSERT INTO  `report` (`med_id`,`pat_id`,`dtime`,`responsible`,`status`) values(:m_id,:p_id,:time,:by,'3')"
            );
            
            $insert_report->bindparam(':m_id',$drug_id);
            $insert_report->bindparam(':p_id',$pat_id);
            $insert_report->bindparam(':time',$end_time);
            $insert_report->bindparam(':by',$by);
            $insert_report->execute();
    
            $mail = new PHPMailer();
            $mail->isSMTP();
            $mail-> SMTPOptions = array (
                'ssl' => array (
                'verify_peer' => false,
                'verify_peer_name' => false,
                'allow_self_signed' => true
              )
            );
            $mail->Host = "smtp.gmail.com";
            $mail->SMTPAuth = true;
            $mail->SMTPSecure = "tls";
            $mail->Port = "587";
            $mail->Username = "from@gmail.com";
            $mail->Password = "12345678";
            $mail->Subject = "Medication Report";
            $mail->setFrom("from@gmail.com",$by);
            $mail->isHTML(true);
            //Attachment
            //$mail->addAttachment('img/attachment.png');
            //Email body
            $mail->Body = "<h3>Medication Report by ($by) </h3></br>
                            You are being alerted that <b>$by</b> has missed their $directions Medication $row->med_type. And you may need to take appropriate action..";
            $mail->addAddress($to_email['Email_add']);
            $mail->send();
        }
    } // while($row = ...     
} //while $timingRow = ...
Related