[SOLVED] Using Swiftmailer to send bulk messages with CRON

Swift Mailer is a fantastic library for sending email with php. Discuss this library or ask any questions about it here.

Moderators: Chris Corbyn, General Moderators

User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Post by fishnyc22 »

Whoops... I got it. I had the SEND outside the DoWhile Loop. Works PERFECTLY!. This is awesome. I love how it runs the batchs in one query and still uses one set of IDs to update the database...

Though I have thanked you alot over the past few days.... It can't nearly be enough. All your help is greatly appreciated :)
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Post by fishnyc22 »

I just noticed that when there is only one record in the database to send out I get this error:

Code: Select all

Fatal error: Call to a member function on a non-object in /var/www/vhosts/domain.com/httpdocs/util/lib/swift/Swift/BatchMailer.php on line 169
It doesn not happen when there is more than one. Line 169 of BatchMailer.php is

Code: Select all

$message->headers->set("To", "");
EDIT:
However the message does go out. But it does not update the value in the DB to 'S'. So something is killing before that
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Post by fishnyc22 »

OK, I figured it out.

Where there was only one record in the recordset, the doWhile loop was reseting the batch because at first pass $data_pos = 0 and $num_rows = 1.... so $message, $sender were set to null so it ran another cycle and failed the inner while loop, but tried to send the batch after the while loop.

I fixed it by changing this line and adding "&& $num_rows > 1" so it stops there when the record set is only one row.

Code: Select all

} while ($data_pos < $num_rows && $num_rows > 1); //Only while we're not at the end of the resultset
Thats should do the trick.
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Post by fishnyc22 »

Dang.. I take that back. Still getting that bug.

EDIT: I think I resolved it however. Does this make sense??? Seems that when I set the doWhile loop to be the following, It solved the problem.

Code: Select all

} while ($data_pos < $num_rows-1); //Only while we're not at the end of the resultset
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

fishnyc22 wrote:EDIT: I think I resolved it however. Does this make sense??? Seems that when I set the doWhile loop to be the following, It solved the problem.

Code: Select all

} while ($data_pos < $num_rows-1); //Only while we're not at the end of the resultset
I think that makes sense. Where I first declare "$data_pos = -1;" I initially had it to 0 but started to think it probably needed to be -1 due to the way I increment it in the loop. I guess 0 was correct in the first place :) In fact, yes, when you break it down to just one row of input and do the logic using zero to start it works perfectly.
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Post by fishnyc22 »

Right, that would make more sense.... I guess I backwards solved it:)

Thanks
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Re: [SOLVED] Using Swiftmailer to send bulk messages with CRON

Post by fishnyc22 »

Hey Chris, A while back you helped me out A LOT with this. Just thought I would check in with a bit of advise. First off. Last I spoke to you, you were raising money for a trip Down Under. Now I see your location is DOWN UNDER... did you move. Good stuff man. I guess you had a good walk about :)

Anyway. This is my problem. I've been randomly getting these errors when running my script:

Code: Select all

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 5
This is my script. Not sure if you can see anything here thats causing it but its driving me crazy. The error doesnt give me much info, but I thought maybe you may have an idea. I'm wondering if maybe its happening on and off when they failure array is hit. I've never actually gotten a -1 in my db's status column.

Code: Select all

$max_size = 100; 
 
$sql = "
SELECT 
    Q.id,
    Q.msg_id,
    M.m_subject,
    M.m_message,
    A.ag_shortname,
    A.ag_nickname,
    Q.to_id,
    Q.to_email,
    Q.to_name 
FROM 
    `bt_sms_queue` AS Q,
    `bt_messages` AS M,
    `members` AS A 
WHERE 
    A.member_id = M.m_agid 
    AND Q.msg_id = M.mid 
    AND M.mailserver = 2 
    AND Q.status = 0
ORDER BY 
    Q.msg_id 
LIMIT " . $max_size;
 
$result = mysql_query($sql, $connection) or die(mysql_error()); 
$num_rows = mysql_num_rows($result); 
 
$data_pos = 1; //Current position in the resultset 
$ids = array(); 
 
//Nothing to do if no data 
if ($num_rows > 0) 
{
    $swift =& new Swift(new Swift_Connection_SMTP("localhost")); 
    $batch =& new Swift_BatchMailer($swift); 
  do 
  { 
   //Build up a list of recipients 
   $list =& new Swift_RecipientList(); 
   $message = NULL; 
   $sender = NULL; 
   $message_id = -1; //For tracking in the loop 
 
    while ($row = mysql_fetch_assoc($result)) 
    {
      $data_pos++; 
        //Not the same message anymore -- different batch 
        if ($message_id > -1 && $row["msg_id"] != $message_id) 
        { 
          mysql_data_seek($result, --$data_pos); //Backtrack ready for next batch 
        break; //Just this loop
        } 
        $message_id = $row["msg_id"]; //Keep watching!
        
    //No need to repeatedly create $message or $sender in the loop
     if ($message === NULL) $message =& new Swift_Message($row["m_subject"], $row["m_message"]); 
     if ($sender === NULL) $sender =& new Swift_Address($row["ag_shortname"]."@domain.com",$row["ag_nickname"] ); 
     $list->addTo($row["to_email"], $row["to_name"]);
     
     //Collect recipient IDs for use later
     $ids[] = $row["id"];
    } 
 
    //Send this batch 
    $batch->send($message, $list, $sender); 
 
    } while ($data_pos < $num_rows); //Only while we're not at the end of the resultset 
    
    
    //If we have any records to update 
    if (!empty($ids)) 
    { 
     //Some may have failed, some may not 
     $failures = $batch->getFailedRecipients(); 
     foreach ($failures as $key => $value) 
     { 
      //Filter for use in SQL (and add single quotes) 
      $failures[$key] = "'" . mysql_real_escape_string($value) . "'"; 
     } 
 
    //Update all that have NOT failed to 'S' 
    $sql2 = " 
    UPDATE bt_sms_queue 
    SET status = 1 
    WHERE 
      id IN (" . @implode(",", $ids) . ")"; 
    if (!empty($failures)) 
    { 
      $sql2 .= " AND to_email NOT IN (" . implode(",", $failures) . ")"; 
    } 
    mysql_query($sql2, $connection) or die(mysql_error()); 
 
    //Update all that have failed to 'F' 
    if (!empty($failures)) 
    { 
      $sql3 = " 
      UPDATE bt_sms_queue 
      SET status = -1 
      WHERE 
        id IN (" . implode(",", $ids) . " AND to_email IN (" . implode(",", $failures) . ")"; 
      mysql_query($sql3, $connection) or die(mysql_error()); 
    } 
  } 
}
Anyway. Any input is appreciated. Hope you're doing well.

dave
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Re: [SOLVED] Using Swiftmailer to send bulk messages with CRON

Post by fishnyc22 »

Actually, while I hopefully have your attention. I also have seen this error here and there.

Code: Select all

<br />
<b>Warning</b>:  mysql_data_seek(): Offset 2 is invalid for MySQL result index 57 (or the query data is unbuffered) in <b>/var/www/vhosts/domain.com/httpdocs/sender.php</b> on line <b>75</b><br />
I'm guessing that its the server being overloaded. our usage has gone up a bit. maybe our server is a bit over worked.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: [SOLVED] Using Swiftmailer to send bulk messages with CRON

Post by Chris Corbyn »

I can't see which query that error is coming from at a glance. Maybe add some text to the die() statements to identify each on separately, or perhaps use trigger_error() so you get the line number? :)

The mysql_data_seek() error looks valid. I don't think an overworked server would affect it... it's suggesting that the resultset you're trying to seek on doesn't have 3 rows of data in it ;)
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Re: [SOLVED] Using Swiftmailer to send bulk messages with CRON

Post by fishnyc22 »

Yeah I probably should have thought to do that. Thanks for the tip.
From that. I found that its the 3rd query that is causing the error:

Code: Select all

if (!empty($failures)) 
    { 
        $sql3 = " 
      UPDATE bt_sms_queue 
      SET status = -1 
      WHERE 
        id IN (" . implode(",", $ids) . " AND to_email IN (" . implode(",", $failures) . ")"; 
      mysql_query($sql3, $connection) or die("Query3: " . mysql_error()); 
    }
I put in a few print_r() before the query to see what values are getting passed in:

$ids had these values:

Code: Select all

 
Array
(
   [0] => 688519
   [1] => 688518
   [2] => 688514
   [3] => 688482
   [4] => 688481
   [5] => 688477
   [6] => 688475
   [7] => 688474
   [8] => 688470
   [9] => 688469
   [10] => 688468
   [11] => 688467
   [12] => 688466
   [13] => 688465
   [14] => 688464
   [15] => 688463
   [16] => 688462
   [17] => 688461
   [18] => 688460
   [19] => 688459
   [20] => 688458
   [21] => 688457
   [22] => 688456
   [23] => 688455
   [24] => 688454
   [25] => 688453
   [26] => 688452
   [27] => 688451
   [28] => 688450
   [29] => 688449
   [30] => 688448
   [31] => 688447
   [32] => 688446
   [33] => 688445
   [34] => 688444
   [35] => 688443
   [36] => 688442
   [37] => 688441
   [38] => 688440
   [39] => 688439
   [40] => 688438
   [41] => 688437
   [42] => 688436
   [43] => 688435
   [44] => 688434
   [45] => 688433
)
 
$failures has these values:

Code: Select all

 
 
Array
(
   [0] => 'NUMBER@messaging.sprintpcs.com'
   [1] => 'NUMBER@messaging.sprintpcs.com'
   [2] => 'NUMBER@messaging.sprintpcs.com'
   [3] => 'NUMBER@messaging.sprintpcs.com'
   [4] => 'NUMBER@messaging.sprintpcs.com'
   [5] => 'NUMBER@messaging.sprintpcs.com'
   [6] => 'NUMBER@mobile.mycingular.com'
   [7] => 'NUMBER@messaging.sprintpcs.com'
   [8] => 'NUMBER@messaging.sprintpcs.com'
   [9] => 'NUMBER@messaging.sprintpcs.com'
   [10] => 'NUMBER@mobile.mycingular.com'
   [11] => 'NUMBER@mobile.mycingular.com'
   [12] => 'NUMBER@mobile.mycingular.com'
   [13] => 'NUMBER@messaging.sprintpcs.com'
   [14] => 'NUMBER@messaging.sprintpcs.com'
   [15] => 'NUMBER@mobile.mycingular.com'
   [16] => 'NUMBER@messaging.nextel.com'
   [17] => 'NUMBER@tmomail.net'
   [18] => 'NUMBER@messaging.sprintpcs.com'
)
 
Do you see ANYTHING that would cause the error? Any feedback appreciated.

Fish
><>
User avatar
fishnyc22
Forum Commoner
Posts: 38
Joined: Wed May 30, 2007 6:20 pm

Re: [SOLVED] Using Swiftmailer to send bulk messages with CRON

Post by fishnyc22 »

I outputted the query to see what it looks like and found I was missing a closing ")" in the first IN statement.
Thanks for the suggestion and the help!
Post Reply