How to send a large email? - php

$i = 1;
foreach ($recipients as $email => $name) {
$mail->ClearAddresses();
$mail->AddBCC($email, $name);
if (!$mail->send()) {
$send = 0;
} else {
$send = 1;
}
$query = "INSERT INTO `newsletter_send`(`email`, `id_newsletter`, `date`, `send`) VALUES ('$email',$id_newsletter, NOW(),$send) ";
$stmt = $link->prepare($query) or die('error');
$stmt->execute();
$mail->clearAllRecipients();
if (($i % 100) == 0) {
sleep(60);
}
$i++;
}
What is the best way to send a large emails without sleep() and without to wait the page to finish loading? In addition to the cron job you have other ideas ?
EDIT: I have 680 users who will receive the email, but after a while I get 500 Internal Server Error.. why? It maybe time_limit?

Message queues.
beanstalkd is a good solution.
You can then use a SDK like pheanstalk to handle the queue and its jobs.
EDIT: If you have restricted access to your server (for example, if you are using a shared hosting) message queues as a service are also an option.
IronMQ
CloudAMQP
AWS (Amazon Web Services) SQS

A good way to send a large amount of emails at a fast pace is to have a lot of worker scripts doing the job instead of 1 php page (GiamPy gave a good example for one of the ways that can be done and I won't mention it since I don't want to be redundant).
One simple (though somewhat hacky) option is: for you to make 20 php scripts in a file. You could name them mailer1.php, mailer1.php, ..., mailer20.php. Then, you could create a folder called mail and put two files inside:
mail/config.txt
and
mail/email.txt
Inside mail/config.txt, you would include the following lines of text:
T
15
where the first line has a T for TRUE meaning you want the mailers to send the mail out as fast as they can in intervals of 15 seconds each. You can obviously change the interval time as well to whatever you like.
And in mail/email.txt you would have the complete email you want to send
After having done all that you make the mailer files. You can make 1 first, write the code, and then copy paste it 19 times to have 20 scripts in total. The code inside could look something like this:
<?php
$pathconfig = "mail/config.txt";
$pathemail = "mail/email.txt";
$email = file_get_contents($pathemail);//now you have the email saved
$filehandleconfig = fopen($pathconfig, "r");
$bool = trim(fgets($pathconfig));
$sleeptime = (integer) trim(fgets($pathconfig));
fclose($filehandleconfig);
while ($bool === 'T')
{
//... code that sends the email
//recheck if 'T' is still 'T':
$filehandleconfig = fopen($pathconfig, "r");
$bool = trim(fgets($pathconfig));
fclose($filehandleconfig);
sleep($sleeptime);
}
?>
So what the previous code would basically do is extract the email that needs to be sent at the beginning, and also extract the time it will sleep after sending an email, and if it should continue to send emails.
What that means is that the mail/config.txt file is your controlpanel, and if you change 'T' to be anything else that 'T' (like 'F' for instance), then all the scripts will terminate.
The downside to this option is that it's a bit hacky, though the upside is that it can be developed in a matter of minutes.

Related

send mail via php yii until success on time

i have php function that send mail on special time ever 7 days but when i send mail its sometimes not sent because server busy or not available ,my question is how to try send my email many times when its something wrong every 10 minute until its send success
private function sendEMailMessage($args) {
$failed = true;
for($i = 0; $i < 5 && $failed; $i ++) {
$failed = Utilities::sendEMailMessage ( $args ) != '';
if ($failed) {
sleep ( 15 );
}
}
}
//its this work or not ???
The another way you can do this is setting a flag in database table. Based on the flag value you can send/resend the email. On successful sending of email you can delete or reset the flag .
The best way to deal with this problem would be to set up cron jobs for every 7 days.And for the mail sometimes getting not sent purpose you could use this,
if (Yii::$app->mailer->getTransport()->isStarted()) {
Yii::$app->mailer->getTransport()->stop();}
Yii::$app->mailer->getTransport()->start();
If this is included in your yii app then once the mail is sent it should clear the ssl socket layer and open a fresh socket again for the next time.With the combined use of these I think it should work.

How to send x number of email using phpMailer?

I have a job site (in CI) and there can be x number of jobseekers.What i have to do is send revalent jobs according to users job category and location.So there is different message for different jobseeker.
i am using phpMailer to send email for now i have done
$subject = 'Revalent Jobs For Your Profile';
foreach ($job_receiving_users as $job_receiving_user){
$this->send_email->send_email(FROM_NOREPLY_EMAIL,ORG_NAME,$job_receiving_user['email'],$job_receiving_user['username'],$subject,$job_receiving_user['message']);
$time = time() + 10;
while( time() < $time){
// do nothing, just wait for 10 seconds to elapse
}
}
(There is phpMailer email sending method inside library send_email)
There is limit of 200 email per hour from server or can extend it to 500.
What i want to know is this good way to send email?
if i keep 10secod gap between every email will it keep my server busy.All sql actions were done above this code and $job_receiving_users is array of user email,message and username extracted above.
Base your code on the mailing list example provided with PHPMailer
What you're doing in your loop is called "busy waiting"; don't do it. PHP has several sleep functions; use them instead. For example:
$sendrate = 200; //Messages per hour
$delay = 1 / ($sendrate / 3600) * 1000000; //Microseconds per message
foreach ($job_receiving_users as $job_receiving_user) {
//$this->send_email->send_email(FROM_NOREPLY_EMAIL,ORG_NAME,$job_receiving_user['email'],$job_receiving_user['username'],$subject,$job_receiving_user['message']);
usleep($delay);
}
This will cause it to send a message every 18 seconds (200/hour), and the use of the sleep function will mean it consumes almost no CPU while it's waiting.

How can I send an email to lots of users using a proper way in CodeIgniter 3

I need some advice because I am building a subscription module. And I have a list of so many emails. Let say 1052 emails. And I have a code like this:
$email_list = $this->getClientEmails(); //all email for now returns 1052 valid emails
$valid_email = array();
$invalid_email = array();
if(count($email_list) > 0) {
for($x = 0; $x < count($email_list); $x++) {
if(valid_email($email_list[$x]['email'])) {
$valid_email[] = $email_list[$x]['email'];
}
//get all invalid emails
/*else {
$invalid_email[] = array(
'id' => $email_list[$x]['id'],
'email' => $email_list[$x]['email']
);
}*/
}
}
$email_string = implode(',', $valid_email);
$this->email->set_mailtype("html");
$this->email->from($from, 'Sample Admin');
$this->email->to($email_string); //send an email to 1052 users
$this->email->cc('test#sampleemail.com.ph');
$this->email->subject($subj);
$this->email->message($content);
$send_mail = $this->email->send();
if($send_mail) {
fp('success');
} else {
fp('failed');
}
Is it fine if I send an email like this? Or should I make a loop to send my email to different users? Means I will not use my imploded string. I will do the sending once in every week. And also what if the sending of email suddenly stops in the middle what should I do? Do I need to resend it again? Or should I make a column in my table that will update if the email is sent or not?
Can you give me some advice about this? That's all thanks.
Okay because you have a mailing list the first thing that i would recommend is that you push the script to background. Use selinium or cron for the same that way page render won't get stuck.
Once done You can send emails either way, send to multiple people or one at a time, both of them are valid and won't cause any problem. The point you need to consider here is the SMTP connection that you maintain.
If you are sending them all individually, you don't want to close connection to SMTP server and reconnect every time to send the mail which would only cause the overhead.
I should say that from your case the most valid way to send email is make a queue on some database preferably redis and have a task handle them in background (cron job if you are on cpanel or selinium if you own the server)
Finally this is a part that you might wanna test out. Because you have a mailing list i am guessing you don't want people to see through your whole list so check the headers when you are sending mails to all at once and if you don't see email from other users , you are good to go else send to each of them separately.
Also one final thing, emails not being delivered is usually bounced which may reflect bad on your server so have a script that flags emails that are constantly rejected and stop sending mails to the same or your ip address might end with bad repo and mails might end up in spam.
Have you thought of using PHPMailer as a library on your CodeIgniter installation?
You could just do it like this:
if(count($email_list) > 0) {
for($x = 0; $x < count($email_list); $x++) {
if(valid_email($email_list[$x]['email'])) {
$mail->addAddress($email_list[$x]['email'], $x);
}
}
}
Please refer to this example on how to use PHPMailer.
I hope this helps, or at least that it gives you a different perspective on how can this be done.
Referring to:
Or should I make a column in my table that will update if the email is sent or not?
Yes, I think that if you want to control if an email has been sent you should use a 1 character field on your table as a "flag" to corroborate that the email has been sent to your users.

Prevent PHP from sending multiple emails when running parallel instances

This is more of a logic question than language question, though the approach might vary depending on the language. In this instance I'm using Actionscript and PHP.
I have a flash graphic that is getting data stored in a mysql database served from a PHP script. This part is working fine. It cycles through database entries every time it is fired.
The graphic is not on a website, but is being used at 5 locations, set to load and run at regular intervals (all 5 locations fire at the same time, or at least within <500ms of each-other). This is real-time info, so time is of the essence, currently the script loads and parses at all 5 locations between 30ms-300ms (depending on the distance from the server)
I was originally having a pagination problem, where each of the 5 locations would pull a different database entry since i was moving to the next entry every time the script runs. I solved this by setting the script to only move to the next entry after a certain amount of time passed, solving the problem.
However, I also need the script to send an email every time it displays a new entry, I only want it to send one email. I've attempted to solve this by adding a "has been emailed" boolean to the database. But, since all the scripts run at the same time, this rarely works (it does sometimes). Most of the time I get 5 emails sent. The timeliness of sending this email doesn't have to be as fast as the graphic gets info from the script, 5-10 second delay is fine.
I've been trying to come up with a solution for this. Currently I'm thinking of spawning a python script through PHP, that has a random delay (between 2 and 5 seconds) hopefully alleviating the problem. However, I'm not quite sure how to run exec() command from php without the script waiting for the command to finish. Or, is there a better way to accomplish this?
UPDATE: here is my current logic (relevant code only):
//get the top "unread" information from the database
$query="SELECT * FROM database WHERE Read = '0' ORDER BY Entry ASC LIMIT 1";
//DATA
$emailed = $row["emailed"];
$Entry = $row["databaseEntryID"];
if($emailed == 0)
{
**CODE TO SEND EMAIL**
$EmailSent="UPDATE database SET emailed = '1' WHERE databaseEntryID = '$Entry'";
$mysqli->query($EmailSent);
}
Thanks!
You need to use some kind of locking. E.g. database locking
function send_email_sync($message)
{
sql_query("UPDATE email_table SET email_sent=1 WHERE email_sent=0");
$result = FALSE;
if(number_of_affacted_rows() == 1) {
send_email_now($message);
$result = TRUE;
}
return $result;
}
The functions sql_query and number_of_affected_rows need to be adapted to your particular database.
Old answer:
Use file-based locking: (only works if the script only runs on a single server)
function send_email_sync($message)
{
$fd = fopen(__FILE__, "r");
if(!$fd) {
die("something bad happened in ".__FILE__.":".__LINE__);
}
$result = FALSE;
if(flock($fd, LOCK_EX | LOCK_NB)) {
if(!email_has_already_been_sent()) {
actually_send_email($message);
mark_email_as_sent();
$result = TRUE; //email has been sent
}
flock($fd, LOCK_UN);
}
fclose($fd);
return $result;
}
You will need to lock the row in your database by using a transaction.
psuedo code:
Start transaction
select row .. for update
update row
commit
if (mysqli_affected_rows ( $connection )) >1
send_email();

PHP trigger an email automatically when a certain condition is met

I would like to automate the process of sending this email. I mean when a condition is met then the email should automatically be sent to the given email addresses which is already given as hard-coded values. So for an example in my case a Technician has to complete 40jobs a day and if he finished 35 at the end of the day an email should be sent to the supervisor(provided his email id is already given) with Subject name and the body should be like ” The Technician 1234 has completed only 35 jobs for the day instead of 40. I was wondering how can implement this as Im very new to the field of PHP. Please anyone help me out. If possible please provide me with an example.
Thanks
Dilip
You could run a cron that uses the php mail function to send a report about each programmer at a set time each day. The cron script would look something like:
<?php
$to = 'admin#mydomain.com';//the set up email to mail too
$result = mysql_query('select programmer_id, job_count, job_requirement from table'); //query the database
while($job = mysql_fetch_object($result)){
mail($to,'Job counts for ' . $job->programmer_id,"Completed $job->job_count out of $job->job_requirement jobs","FROM: jobcounter#mydomain.com");
}
Have a script check the conditions and send emails, and run it periodically: http://www.google.com/search?q=cronjob
I'm assuming here that your problem is the triggering of the event, rather than the sending of the email itself.
In the example you described, you would need to have a script run at a certain time of day that would check for any condition that would require an email sending, and then send the email. Under any unix-like system, cron is the ideal solution to this. If you are on some kind of basic shared hosting you may not be able to set this up. In that case you would need to set up a task to run on a machine that you do have control over that would call a URL that would run the PHP script. This could be a cronjob, or a Scheduled Task under Windows.
If your example was switched around so that, say, an email was to be sent as soon as a technician completed 40 jobs then you would be able to send the email as part of the script that handled the form submission from the technician whenever he completed a task.
Setup a Cron Job that runs at the "end of the day":
23 55 * * * /path/to/php /path/to/script.php
Have it run a PHP script that can query your Job Store for whatever condition you want to check. For example with Job Store being a database.
$db = new PDO(/* config */);
$result = $pdo->query(
'SELECT count(id) as "tasks_done"
FROM tasks WHERE engineer = "Tom"
AND finished_at = now()');
$result = $result->fetchAll();
if($result[0]['tasks_done'] < 40) {
mail( ... )
}
If the condition is met, send the mail. The above needs refining of course. Dont expect being able to copy/paste it.
Also see:
What is the best method for scheduled tasks in PHP
http://greenservr.com/projects/crontab/crontab.phps
you should use mail() function:
$technicianId = 1234;
$jobsNeeded = 40;
$jobsDone = getJobsDone($technicianId);
if ($jobsDone <= $jobsNeeded) {
mail('supervisor#yourcompany.com', 'Technician '.$technicianId.' slacking', 'The Technician '.$technicianId.' has completed only '.$jobsDone.' jobs for the day instead of '.$jobsNeeded);
}
Could have a cronjob that runs at the end of each day which checks what each technician has done and emails it to the manager.

Categories