Sending multiple mails

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
hytechpro
Forum Newbie
Posts: 6
Joined: Fri Sep 16, 2005 7:41 am
Location: INDIA

Sending multiple mails

Post by hytechpro »

Hello Friends,

I want to know how to send mails to multiple email addresses using PHP code.

Thanks.

Vishal Gupta
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

use the CC header (carbon copy), or the BCC (if you do not want the recipients to know it's a mass mailing). this only works if it's the same message to all, if the message changes for each recipient you need to put the recipients in an array and use a foreach loop
User avatar
m3mn0n
PHP Evangelist
Posts: 3548
Joined: Tue Aug 13, 2002 3:35 pm
Location: Calgary, Canada

Post by m3mn0n »

Take a look at the examples on this page: http://www.php.net/mail

And then what you do is extract the people who are going to get the mail into an array (see: http://www.php.net/arrays).

And then from the array with the e-mail address, loop through it using foreach() loop (for example, there is other ways).

Then in the loop, use the code on that mail page but replace the value of the recipient with the value from the array.

This is only good for a couple hundred people at the most. Any more and you'll experience very slow loading times. So it's best to split up the sending into chunks if you are sending it to multiple thousands of people.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

sami you're too sloooooowwww :wink:
anyways just thought I'd add you should put

Code: Select all

set_time_limit(0);
at the top of your script so it can keep on running without timing out, but beware... if you invoke an infinite loop and you have set the time limit to unlimited you will have to restart apache. You can also use a function called array_chunk() for splitting arrays into chunks, of say 50 emails at a time then use the function called sleep() to wait a certain amount of time... say 60 seconds, that way after every 50 mails it fires off it waits for a little while..


as you can see using the BCC is the easiest because it's just one call to mail
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

It would be a wiser choice to limit the number of emails sent in one chunk in my opinion. To the user it will just look like it has hung/crashed and if they refresh their user agent you might end up with multiple duplicates.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Post by matthijs »

jshpro2, how would you use that array_chunk() function?

A solution with the sleep() function I have seen is:

Code: Select all

$x = 1;
$hold = 50; // quantity of emails sent before 3 sec delay
$emails = mysql_query("SELECT email FROM members");
while ($sendemail = mysql_fetch_array($emails)) 
{
    $email = $sendemail["email"];
    mail($email, $subject,
    $message, "From:Your name <you@whatever.com>");

    $x++;
    if($x == $hold) 
    {  // When $x is equal to $hold, a 3 sec delay will occur avoiding php to timeout
        sleep(3);
        $x = 0;
    }
}
As suggested, sending the mails as bcc: would be faster. But I've also heard that that could give problems with the emails being seen as spam?

Jenk's suggestion "limit the number of emails sent in one chunk in my opinion" also seems like a good one.
Would it be a good idea to place a rule in a loop which changes the value of a field "sent" in the emails table from 0 to 1. Then when the user wants to sent the next (100?) emails the loop skips the email address fields with "sent"value 1, and takes the next 100 with value "sent" 0. I'm just thinking aloud here, don't know if this is a good solution.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

It's highly recommended to not use the mail function for mass mailing, as each call will make a new connection to the smtp server or sendmail, resulting is massive time delay.. Instead use something like phpmailer.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

Matt, that solution is semantically the same to the array_chunk, instead of "ticking" X each iteration and waiting till it gets to 50, I just woulda split the array into sub-arrays with 50 elements so I don't have to keep track of $x..

Any reason you don't just put all the emails in the BCC? Or do what feyd said?
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Post by matthijs »

jshpro2, you're correct. I have taken a look at array_chunk function and it probably easier to use then some x++ loop.

Something like this maybe (comments are welcome!)?

Code: Select all

// this comes from a db normally
$input_array = array('email1', 'email2', 'email3', 'email4', 'email5', 'email6'); 
$chunks = array_chunk($input_array, 2);

foreach ($chunks as $key => $value)
{
    foreach ($value as $key2 => $email)
    {
    mail($email, $subject, $message, "From:Your name <you@whatever.com>");
    }
    sleep(3);
}
The reason I said BCC might not work that well, is that I've read in some places that emails being sent as bcc: could be recognized as spam easier. But I might be totally wrong here. Please correct me if so.
Or do what feyd said?
You mean using phpmailer?

In fact in the mailingslist script I'm writing I do use phpmailer. However, if I'm understand it correctly: even though the use of phpmailer will make the process of mailing very easy and phpmailer does a lot of the work for you, some sort of loop is still necessary to sent all the emails. At least, that's what I understand from a tutorial on phpfreaks:
http://www.phpfreaks.com/tutorials/130/8.php

Code: Select all

// instantiate the class
$mailer = new FreakMailer();

// Get the user's Email
$sql = mysql_query("SELECT FirstName,LastName,EmailAddress,MailType FROM users WHERE 1");

while($row = mysql_fetch_object($sql))
{
  // Send the emails in this loop.
  $member_name = $row->FirstName;
  if(!empty($row->LastName))
  {
    $member_name .= ' '.$row->LastName;
  }
  
  if($row->MailType == 'html')
  {
    $mailer->Body = str_replace('{MEMBER_NAME}', $member_name, $htmlBody);
    $mailer->IsHTML(true);
    $mailer->AltBody = str_replace('{MEMBER_NAME}', $member_name, $textBody);
  }
  else
  {
    $mailer->Body = str_replace('{MEMBER_NAME}', $member_name, $textBody);
    $mailer->isHTML(false);
  }
  $mailer->Send();
  $mailer->ClearAddresses();
  $mailer->ClearAttachments();
  $mailer->IsHTML(false);
  echo "Mail sent to: $member_name<br />";
}
Or am I missing some information? Feyd, could you explain why using phpmailer would be better? Does phpmailer not make new connections to the smtp server for each mail?
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

Well the recipients mail agent (hotmail, outlook, etc...) cannot detect the BCC, that's why it stands for blind carbon copy. Some MTA's on the way might truncate the list of BCC's though, so that's not good now that I think of it
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Post by matthijs »

I have added a bit of code to my mailinglist script. It uses the phpmailer class to send the mails. The emails and names come from a db. I added the set_time_limit() and sleep() functions in the loop. The loop is broken in chunks using the array_chunk function suggested by jshpro2.

I hope some of you want to take a look at my code. It is meant for a very simple mailinglist script. I don't expect to use it for large amounts of mail, maybe hundreds. From what I understand so far, mailing thousands will be problematic without using a cron job or some other way.

Code: Select all

<?php
set_time_limit(300); // 5 minutes

if(isset($_POST['submit']))
{
    //  validation of $_post values here....


    /*-------------------------------------------------------
      If all is well process the mail
    ----------------------------------------------------------*/ 

    // Setup body
    $textBody = "Dear {MEMBER_NAME},\n\nCheck out PHP Freaks: http://www.phpfreaks.com\n\nSincerely,\nAdmin";
    $htmlBody = "Dear {MEMBER_NAME},<br /><br />Check out this <b>html</b> mail from PHP Freaks: http://www.phpfreaks.com<br /><br />Sincerely,<br />Admin";

    // instantiate the class
    $mailer = new FreakMailer();

    $mailer->Subject = 'This is a test';
		
		
    // Get the user's Email
    $sql = 'SELECT FirstName,LastName,EmailAddress,MailType FROM mymaillist_subscribers';
    $result = $db->query($sql); // create MySQLResult object. I use a MySQL class from the php anthology books
    
    $mails = array();
    
    while ($rows = $result->fetch()) {
       $mails[] = $rows;
    }

    $chunks = array_chunk($mails, 10);
	  
    foreach($chunks as $value)
    {
        foreach($value as $row) 
        {
		      
            // Send the emails in this loop.
            $member_firstname = $row['FirstName'];
            $member_address = $row['EmailAddress'];
            $mailer->AddAddress($member_address);
            if(!empty($row['LastName']))
            {
               $member_name .= ' '.$row['LastName'];
            }
    
            if($row['MailType'] == 'html')
            {
                $mailer->Body = str_replace('{MEMBER_NAME}', $member_name, $htmlBody);
                $mailer->IsHTML(true);
                $mailer->AltBody = str_replace('{MEMBER_NAME}', $member_name, $textBody);
            }
            else
            {
                $mailer->Body = str_replace('{MEMBER_NAME}', $member_name, $textBody);
                $mailer->isHTML(false);
            }

            $mailer->Send();
            $mailer->ClearAddresses();
            $mailer->ClearAttachments();
            $mailer->IsHTML(false);
            echo "Mail sent to: $member_name<br />";
        }

        // Have the loop sleep a few secs 
        sleep(5);
    }

}
?>
As you can see, in the example above I've set the set_time_limit to 5 minutes. I could change that to a larger value.

Using the array_chunk i split the array coming out of the db in chunks of 10 emails. That could be more (50? 100?).

I sleep for 5 sec in each foreach loop.

Thanks for any feedback!
Post Reply