Sending an Email through PHP using a Db

He has: 1,380 posts

Joined: Feb 2002

Hey, how would i send an email to a large group of email addresses, taken from a dB? I have a form setup, which would contain the body, but what would be the send-to? You know what I'm saying? Any help would be great. Thanks.

He has: 296 posts

Joined: May 2002

<?php
$query
= mysql_query(\"SELECT email FROM users\");
while (
$emails = mysql_fetch_row($query)) {
   
$sendto = (isset($sendto)) ? $sendto.\", \".$emails['email'] : $emails['email'];
}
mail(
$sendto,\"Subject\",\"Body\");
?>

Untested, but that should work.

[James Logsdon]

Renegade's picture

He has: 3,022 posts

Joined: Oct 2002

necrotic wrote:

<?php
$query
= mysql_query(\"SELECT email FROM users\");
while (
$emails = mysql_fetch_row($query)) {
   
$sendto = (isset($sendto)) ? $sendto.\", \".$emails['email'] : $emails['email'];
}
mail(
$sendto,\"Subject\",\"Body\");
?>

Untested, but that should work.

Dude, I think that will only send one email, you need the mail() function in the while() loop body.

<?php
$query
= mysql_query(\"SELECT email FROM users\");
while (
$emails = mysql_fetch_row($query)) {
   
$sendto = (isset($sendto)) ? $sendto.\", \".$emails['email'] : $emails['email'];
    mail(
$sendto,\"Subject\",\"Body\");
}
?>

He has: 1,380 posts

Joined: Feb 2002

ok thanks.

Abhishek Reddy's picture

He has: 3,348 posts

Joined: Jul 2001

heh, Renegade, no. To send multiple emails, you list them as "[email protected], [email protected], [email protected]". James's code creates a comma-separated string of all the email addresses. The mail() function need only be used once; the mailserver handles the multiple addresses. Smiling

The code you provide is dangerous for two reasons. First, it'll send one email to all addresses, for each email address to send to. Not only will this fill up inboxes, but it will likely break the server. Wink Second, when you use the mail() function, you're opening a connection with the mail server, sending data, then closing. Repeating this several times over creates substantial overhead on the server. Read the user notes on the mail function page at php.net for more info.

He has: 1,380 posts

Joined: Feb 2002

lol thanks

Suzanne's picture

She has: 5,507 posts

Joined: Feb 2000

Abhi, that doesn't make sense to me -- I can't send out emails with all the addresses visible, they need to be showing as one email to one recipient. The other option is a "group" name and then having all the emails as a bcc: -- can you explain why sending an email to each recipient would break the server? I wouldn't think that most servers can't handle 150 emails sent out one at a time any more problematically than 150 emails sent at once, barring the additional overhead of multiple mail()?

Abhishek Reddy's picture

He has: 3,348 posts

Joined: Jul 2001

As I understand it...

Suppose there are 200 addresses in the db to send to, the looping code with the stringed addresses will have the server send 200 mails out, 200 times (because the loop repeats it for each address in the db). 200*200 = 40,000. And since it sends to the same addresses, 200 people will theoretically end up with 200 copies of the same email in their inbox.

Why the server breaks is because the PHP mail() function is reasonably inefficient. For the reason that it opens a connection to the Mail Transfer Agent, sends the required mail data to the MTA, then closes the connection. This is fine for sending a few emails, or even for sending a list of emails for the MTA to parse and handle. But with the code in question, it means it will open a connection, send 200 addresses to send to and close the connection (this is fine), but repeat it 200 times (this is not fine).

As noted in the user comments on the ref.mail and function.mail pages on php.net, opening a single socket with the MTA to send multiple mails out is more efficient. Smiling

They have: 461 posts

Joined: Jul 2003

Abhishek Reddy wrote: As I understand it...

Suppose there are 200 addresses in the db to send to, the looping code with the stringed addresses will have the server send 200 mails out, 200 times (because the loop repeats it for each address in the db). 200*200 = 40,000. And since it sends to the same addresses, 200 people will theoretically end up with 200 copies of the same email in their inbox.

Why the server breaks is because the PHP mail() function is reasonably inefficient. For the reason that it opens a connection to the Mail Transfer Agent, sends the required mail data to the MTA, then closes the connection. This is fine for sending a few emails, or even for sending a list of emails for the MTA to parse and handle. But with the code in question, it means it will open a connection, send 200 addresses to send to and close the connection (this is fine), but repeat it 200 times (this is not fine).

As noted in the user comments on the ref.mail and function.mail pages on php.net, opening a single socket with the MTA to send multiple mails out is more efficient. Smiling

either i'm reading the code wrong, or your math is wrong.

i'm reading that in the one with the mail in the loop it adds an address with each loop, thus if there is 200 name,s the first gets 200 emails, the second 199, and thus down to the 200th gets one.

however i also see the point of what suzanne said about the dynamic body, in which case merely changing the script to reset the to feild should make it 200 emails flat int hat situation. and in that cas, do you have a way to send 200 different emails in one call? or would one need to make all 200 calls to the mail function?

personally if everything else was static, i'd build the mailing list as a bcc and send it once with myself in the to feild so that no recipient would see the others, thus protecting privacy

POSIX. because a stable os that doesn't have memory leaks and isn't buggy is always good.

Mark Hensler's picture

He has: 4,048 posts

Joined: Aug 2000

If the body is static (same for all recipients), you may want to consider using an alias on your own domain.

If the body is dynamic (different for all recipients), then you will need to build the body and send it out within a loop.

Which solution do you need?

Mark Hensler
If there is no answer on Google, then there is no question.

Renegade's picture

He has: 3,022 posts

Joined: Oct 2002

So when a user gets the email, the To: field will show 150 addressess?

Suzanne's picture

She has: 5,507 posts

Joined: Feb 2000

Okay, this is important to me to understand -- we have a list of 150 persons. Each email has the same body except for a piece that reminds the person of their personal login ID and a section personalizing the email (Hi, $username).

I *don't* understand how looping through a list of email addresses and composing and then sending an email for each address would result in 150x150?! I'm not making an array of email addresses, just one email address per mail(). In practice, this has resulted in each person getting one copy of the personalized email (I send one to myself as well), containing only that email address (no bcc, no groups, no list) and the server hasn't broken.

What am I not understanding here (reading the references now, I may find the answer there, if so, I'll report back)?

Suzanne's picture

She has: 5,507 posts

Joined: Feb 2000

Alrighty, I see that someone says that using mail() for heavy emailing isn't efficient if it's in a loop. Not that it causes an exponential amount of mailing -- can you quote the relevant part for me, Abhi, I can't seem to find it?

Does heavy emailing mean a big list, or a big email sent to a big list? Would a small text-only email be as big a deal?

druagord's picture

He has: 335 posts

Joined: May 2003

What makes a big deal is how many you send. The best way to preserve server resource is to put all recipient in bcc

Suzanne's picture

She has: 5,507 posts

Joined: Feb 2000

I understand that, but that's not always feasible (see need to personalize each email). I'm less concerned with server resources (unless it will crash the server) than with crashing the user's inbox. The server is there to be used, I see no benefit in conserving what I do with it except whereas it impacts other things I need it for (i.e. I don't conserve food just to conserve it, I conserve food when there is a shortage).

Then again, I send them out monthly, in the middle of the night. Wink

druagord's picture

He has: 335 posts

Joined: May 2003

Sorry i guess i read to fast Smiling

ok the problem is in the code by renegade all address are added to the to field it could be corrected like this.

<?php
$query
= mysql_query(\"SELECT email FROM users\");
while (
$emails = mysql_fetch_row($query)) {
   
$sendto = $emails['email'];/* remove this (isset($sendto)) ?  $sendto.\", \". $emails['email'] :$emails['email'];*/
    mail(
$sendto,\"Subject\",\"Body\");
}
?>

IF , ELSE , WHILE isn't that what life is all about

Suzanne's picture

She has: 5,507 posts

Joined: Feb 2000

We need someone to come through and remove all my questions and make a nice summary of what should actually be done, lol...

Is this right??:

An ideal mass-mailing script made of php wouldn't use mail(), it would use another method. (e.g. Eskator should investigate another method of sending out his emails as he has a large group, such as the function being worked on by grey at greywyvern dot com
?)

You can use mail() in a loop, if you only feed it one email address at a time or use BCC? But beware that over (what, 50?, 100?) emails, you're seriously compromising the efficiency of your server and should look into one of the other options for mass mail outs, such as _________ (sendmail()? using a pipe to the SMTP server?).

A method for using mail(); with a database of email addresses, is:

<?php
// connect to the db
// query the db for all the email addresses and other information needed
// send the email for each address
while ($results = mysql_fetch_row($qry)) {
   
// prepare the message by filling in all the pieces as needed
   
$recipient = $results['email'];
   
mail($recipient,$sender,$subject,$message,$otherheaders);
}
?>

druagord's picture

He has: 335 posts

Joined: May 2003

I use mail() in a loop for a mailling list of about 1000 user and it work fine without any trouble to my server. i group my adresses by 50 in the bcc

so there are around 200 calls to mail() this doesn't stress my server at all

IF , ELSE , WHILE isn't that what life is all about

He has: 296 posts

Joined: May 2002

Woohhh... this turned into a big thread!

So I don't get it: is my code ex. OKAY to use? Or would you want to use BCC instead of TO? I'm not much with server stuff, so it stumps me.

[James Logsdon]

Renegade's picture

He has: 3,022 posts

Joined: Oct 2002

The code that you have is OK to use - just not the one that I gave.

The problem with the one I gave is that it will send the first email then the first and second email then the first, second and third email...so on and so on.

druagord's picture

He has: 335 posts

Joined: May 2003

IMO using BCC is better because it recipients won't be able to get the email adresse of other recipients spammer register themself to mailling list just to get emails. Server wise it make no difference.

IF , ELSE , WHILE isn't that what life is all about

Abhishek Reddy's picture

He has: 3,348 posts

Joined: Jul 2001

Suzanne, I was referring to Renegade's flawed code, which appends an address to the $sendto string, then sends out a set of mails, then appends the next address to $sendto, and then mails once again to the new set. I oversimplified the math so as not to break into this algorithm... it actually sends 200 emails to the first person, 199 to the second, 198 to the third . . . 1 to the last. Smiling

As for efficiency, all reports I've read regarding this indicate that opening a single socket with the MTA (usually sendmail) is more efficient than using mail() repeatedly. I don't have first-hand experience with this so I can't say for myself. I objected to using a repeating mail() script in Renegade's loop since that would send out additional unnecessary mails... which could be dangerous.

Last comment on this page: http://nz2.php.net/manual/en/function.mail.php (lit at matches dot com[b])[/b] as well as the script you quoted, Suzanne.

Suzanne's picture

She has: 5,507 posts

Joined: Feb 2000

*understanding dawns*

Thank you, Abhi! I feel much less confused. It's a bad day when you think you know something, then start doubting yourself. Two Mondays in a row. *sigh*

Mark Hensler's picture

He has: 4,048 posts

Joined: Aug 2000

I've always avoided use of the BCC header in mail scripts. This is because of several (dated) documents that I have read that suggest that the BCC header is not fully and uniformally supported. I suppose the determining factor would be the MTA that you use to initially send out the email, but I have not done any in-depth investigation.

I also recently read that the To, Cc, and Bcc headers have nothing to do with determining where an email is sent to. But that the destination si determined in the SMTP negotiation through the RCPT command.

Imagine a 15 minute intermission while I run to the RFC Editor

Ah ha! I found it in Seciont 3.3 "Mail Transactions" of RFC 2821. Basically, there is an "envelope" which includes a MAIL command ("tells the SMTP-receiver that a new mail transaction is starting"), a RCPT command ("a forward-path identifying one recipient"), then a DATA command. The DATA command contains all information which will be sent to the address identified in the RCPT call. This data also includes the headers of the email (to, cc, bcc, etc.).

Quote: When RFC 822 format [7, 32] is being used, the mail data include the
memo header items such as Date, Subject, To, Cc, From.

I may have dug deaper than necessary. If your scripts work, pay no attention to my bcc phobia. Wink

Mark Hensler
If there is no answer on Google, then there is no question.

Abhishek Reddy's picture

He has: 3,348 posts

Joined: Jul 2001

Mark, I didn't get a word of that. Wink

Is this correct?
- MAIL command initiates a transaction
- RCPT does what? Identify a single primary recipient?
- DATA contains headers which are sent to the RCPT recipient? So one recipient gets all the headers?

At what point are the CC/BCC headers actually processed?

Mark Hensler's picture

He has: 4,048 posts

Joined: Aug 2000

Ok, so maybe I didn't deep enough for some of you. Smiling

From what I've read: yes, yes, and "that can't be true!" (disbelief)

I didn't read the entire RFC, but I think Appendix B is describing how to handle TO, CC, and BCC headers.

   It is recommended that the UA provide its initial ("submission
   client") MTA with an envelope separate from the message itself.
   However, if the envelope is not supplied, SMTP commands SHOULD be
   generated as follows:

   1. Each recipient address from a TO, CC, or BCC header field SHOULD
      be copied to a RCPT command (generating multiple message copies if
      that is required for queuing or delivery).  This includes any
      addresses listed in a RFC 822 "group".  Any BCC fields SHOULD then
      be removed from the headers.  Once this process is completed, the
      remaining headers SHOULD be checked to verify that at least one
      To:, Cc:, or Bcc: header remains.  If none do, then a bcc: header
      with no additional information SHOULD be inserted as specified in
      [32].
'I have the impression that after the MTA recieves a full envelope, it scans the email headers in the DATA section for CC and BCC recipients. Then sends copies of the envelope out to each CC and BCC address (leaving out the BCC headers).

Mark Hensler
If there is no answer on Google, then there is no question.

Mark Hensler's picture

He has: 4,048 posts

Joined: Aug 2000

If the body of the email is different for each recipient, then you need one mail() call per recipient.

Abhishek Reddy's picture

He has: 3,348 posts

Joined: Jul 2001

m3rajk, my math is indeed flawed, as I noted in one of my responses to Suzanne above:

Quote: I said:
Suzanne, I was referring to Renegade's flawed code, which appends an address to the $sendto string, then sends out a set of mails, then appends the next address to $sendto, and then mails once again to the new set. I oversimplified the math so as not to break into this algorithm... it actually sends 200 emails to the first person, 199 to the second, 198 to the third . . . 1 to the last.

Smiling

I don't know how else to send in the case of a dynamic body. Is there no way to construct an array of messages in PHP and send it all to the MTA once and have it mail each to a different address?

How are mails sent to really large lists of addresses in "industrial" situations? I guess some kind of third party software is used?

Suzanne's picture

She has: 5,507 posts

Joined: Feb 2000

I know a number of ISPs will block huge lists of BCCs as well, or terminate them at 150 or some arbitrary number.

I'm also leery of BCCs and somewhat guilty of emphasizing dynamic content so I don't have to deal with them... Wink

Want to join the discussion? Create an account or log in if you already have one. Joining is fast, free and painless! We’ll even whisk you back here when you’ve finished.