-1

Here is my code to send emails with PHPMailer.

It works seamlesly if mailto address is correct.

But if mailto address is incorrect or doesn't exist, the loop stops and will not deliver the rest of the emails on the database.

I guess that what happens is that $mailer->send() throughs an error if email is incorrect, which makes it jump to the catch and the sending of the email is not registered on the database (don't know why it jumps the update query though). This then loops for ever and nothing really happens.

Any ideas on how to fix?

If mailto address doesn't exist I just want to jump it and keep on with the rest of emails, or maybe, register it as sent = 'no' and keep going with the rest.

//SEND EMAIL
$x = 1;

while ($x > 0) {

    $result = $db->query("SELECT * FROM emails WHERE sent = '' AND mailto <> '' ORDER BY id ASC LIMIT 1");

    if (mysqli_num_rows($result)==0) {

        $x = 0;
    
    } else {    

        $row = $result->fetch_assoc();
        $id = $row["id"];

        //Load email data        
        $mailer->AddAddress($row["mailto"]);
        $mailer->Subject = $row["mailsubject"];
        $mailer->Body = $row["mailbody"];

        try {
            
            //Send email
            $mailer->send();
            
            //Register email sent on db
            $update = $db->query("UPDATE IGNORE emails SET sent='yes', date=now() WHERE id='$id'");

        } catch (Exception $e) {
            echo "Message could not be sent. Mailer Error: {$mailer->ErrorInfo}";
            $mailer->getSMTPInstance()->reset(); //Reset the connection to abort sending this message.
        }

        //Clear all addresses and attachments for the next iteration        
        $mailer->clearAddresses();
        $mailer->clearAttachments();

    }
    
    usleep(100000); //sleep for 0.1 seconds
    continue;

}
gzb
  • 1
  • 1
  • **Warning:** You are wide open to [SQL Injections](https://php.net/manual/en/security.database.sql-injection.php) and should use parameterized **prepared statements** instead of manually building your queries. They are provided by [PDO](https://php.net/manual/pdo.prepared-statements.php) or by [MySQLi](https://php.net/manual/mysqli.quickstart.prepared-statements.php). Never trust any kind of input! Even when your queries are executed only by trusted users, [you are still in risk of corrupting your data](http://bobby-tables.com/). [Escaping is not enough!](https://stackoverflow.com/q/32391315) – Dharman Jan 19 '23 at 14:21
  • While it's indeed best practice, there is no SQL injection opportunity in this script. The only variable used in a query is `$id`, and that's sourced internally, not from any user-supplied input, even indirectly. It should of course be validated and probably cast to an int and/or escaped, but there is no vulnerability here. – Synchro Jan 19 '23 at 17:38
  • This is a very strange way to send to a list. You're fetching the whole list, but then only using the first record, marking it as sent, throwing all the rest away, and then starting again. Take a look at [the mailing list example provided with PHPMailer](https://github.com/PHPMailer/PHPMailer/blob/master/examples/mailing_list.phps). – Synchro Jan 19 '23 at 17:44

1 Answers1

0

Ok, solved the problem myself.

In case it helps someone here is the optimised functioning code that will not halt if mailto or mailbcc address is not correct or doesn't exist.

$result = $db->query("SELECT * FROM emails WHERE sent = '' AND mailto <> ''");

foreach ($result as $row) {
    
    $id = $row["id"];
    
    try {
        
        $mailer->addAddress($row['mailto'], $row['mailtoname']);
        
        if (!empty($row["mailbcc"])) {
            $mailer->AddBCC($row["mailbcc"]);
        }
        
        $mailer->Subject = $row["mailsubject"];
        $mailer->Body = $row["mailbody"];
        
        if ($mailer->send()) {
              //Register email sent on db
            $update = $db->query("UPDATE IGNORE emails SET sent='yes', date=now() WHERE id='$id'");

        }
        
    } catch (Exception $e) {
        
        echo "Mailer Error: {$mailer->ErrorInfo}";
        
        //Register that email was not sent so that loop does not stop here
        $update = $db->query("UPDATE IGNORE emails SET sent='no' WHERE id='$id'");
        
        //Reset the connection to abort sending this message. The loop will continue trying to send to the rest of the list
        $mailer->getSMTPInstance()->reset(); 

    }
    
    //Clear all addresses and attachments for the next iteration
    $mailer->clearAddresses();
    $mailer->clearAttachments();

    usleep(100000); //sleep for 0.1 seconds
    continue;
    
}
gzb
  • 1
  • 1