在 while 循环中使用 PHPMailer 发送多封电子邮件

Send Multiple emails with PHPMailer within while loop

我试图在 while 循环中发送多封电子邮件,使用以下代码它不发送电子邮件通知并给出错误 'Fatal error: Uncaught Error: Class "PHPMailer" not found in C:\xampp\htdocs\clinic\paients\run_medications.php:98 Stack trace: #0 {main} thrown in'。虽然位置正确并且它从另一个子目录发送单个电子邮件。

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

您的代码中有:

            $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);

但是如果没有返回任何行并且因此 $check 为 0,则不会设置变量 $by。但是您随后继续使用 $by 进行数据库插入和发送电子邮件的逻辑。我认为如果列 responsible 不可为空,这可能会产生数据库异常。无论如何,这显然是不正确的逻辑。

在执行 while 循环之前,您还对返回的行数进行了大量测试。这些测试确实是多余的:如果返回的行数为 0,如果您只测试返回 FALSE 的 fetch 语句,while 循环将立即退出。因此,可以通过删除那些多余的检查来减少嵌套级别。

第二个问题是您正在从 table users 读取列 name 并将其存储在变量 $by 中。然而,您的电子邮件正文引用了尚未定义的变量 $name。我暂时用 varibale $by 替换了它。但只有你能说这是否正确。但很明显,如果没有,那么您需要用适当的值初始化 $name

$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 = ...

您的 PHPMailerAutoload.php 文件位于何处?

你需要用这个导入它:

require_once('phpmailer/PHPMailerAutoload.php');

总体而言,您必须执行以下步骤:

  • 单击页面右下角的“下载 ZIP”按钮,从 https://github.com/PHPMailer/PHPMailer 下载程序包。

  • 解压缩文件。

  • 上传语言文件夹,class.phpmailer.php、class、pop3.php、class.smtp.php、PHPMailerAutoload.php都放在同一个目录下在你的服务器上,我想在服务器上创建一个名为 phpmailer 的目录来放置所有这些。

  • 在您的项目中加载 class:

    require_once('phpmailer/PHPMailerAutoload.php');

完成...

如果您不使用异常,您仍然需要加载异常 class,因为它在内部使用。

因此,像这样将 use 放在页面顶部(我认为这就是您收到未定义错误的原因):

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

然后像这样调用文件:

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

有时这条线 use PHPMailer\PHPMailer\PHPMailer; 像这样工作 use PHPMailer\PHPMailer; 尝试两种方式。但我认为第一个对你有用。

我不使用 ssl 选项,如果您需要它,只需将它放在 isSMTP 下即可。

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

这里是发送多封邮件的例子:Send multiple email

注意:您必须将您的 gmail 帐户设置为应用安全性较低才能使用 phpmailer。

因为 Gmail 已经开始实施一种身份验证机制,用 SMTP 身份验证代替基于 OAuth2 的授权。 more info

安全性较低的帐户more info , Less secure accounts

据您所知,

Google 正在阻止低安全帐户。