I am using Mailgun to handle email in my Laravel 5.1 application. There are times when I need to email a large number of users at once, such as internal group emails and alert notices. So far, I have created an array of recipient email addresses, sent the email to a webmaster type address, and included the end recipients in BCC:
$recipients = [];
foreach (User::emailRecipients()->get() as $user)
{
$recipients[] = $user->email;
}
$data['message'] = "Hello World";
$data['recipients'] = $recipients;
Mail::send('emails.group-email', $data, function($message) use ($data) {
$message->to('support#demo.com')
->bcc($data['recipients'])
->subject('Test message');
});
While this works, it's not ideal. For starters, I cannot reference anything unique to each recipient within the email (such as a custom unsubscribe link). I cannot use some sort of mailing list on an email provider because the recipients will never be the same, it all depends on several factors.
The next logical step is to iterate over each email address and use Mail::send on each iteration. But would this cause any performance issues or API restrictions with Mailgun? It's possible that one email could be sent to approximately 200 recipients.
Rather than using Laravel's built in Mail, I elected to use Mailgun's API (specifically batch sending) directly - mailgun/mailgun-php
$mailgun = new Mailgun('API-KEY');
$recipientVariables = [
"someone#demo.com" => ['name' => 'Benny'],
"someoneelse#demo.com" => ['name' => 'James']
];
$mailgun->sendMessage('demo.org', [
"from" => 'support#demo.org',
"to" => 'someone#demo.com, someoneelse#demo.com',
"subject" => 'Cool Email',
"html" => $content, // HTML from Blade template
"text" => "Plain text message",
"recipient-variables" => json_encode($recipientVariables)
]);
This also allows me to access unique recipient variables within my email template, like so:
<h1>Hello, %recipient.name%</h1>
I was already passing my Blade template through a CSS inliner, which turns it into plain HTML, so this works perfectly.
Related
I'm using PHP to send mails to multiple people in CakePHP.
I'm currently using foreach on the recipient array, which contains mail address and names, and send the mails. It's taking quite a while to send mails and can't be done as put recipients' mail as array since there's a tiny different between all mails such as receiver's names.
The mails are using same template but different parameters, is there anyway I can improve the efficiency of it?
Update: Here is the Email Template
<?= $userSex ?> <?= $userName ?>, <br>
Thanks for ordering!<br>
Your order's ID is "<?= $orderID ?>".<br>
You can check the shipping status on our website.<br>
Thank you and hope you have a wonderful day.
and here's the code.
$mail_list = {
[0]=>{
'userSex'=>'Miss',
'userName'=>'V',
'orderID'=>'xxxxxxxx'
},
[1]=>{
'userSex'=>'Mr.',
'userName'=>'Arasaka',
'orderID'=>'xxxxxxxx'
}
}
foreach($mail_list as $target) {
$email = new Email();
$email->viewBuilder()->setTemplate('notify_template');
$email->setEmailFormat('html')
->setSubject($subject)
->setViewVars([
'userSex' => $target['userSex'],
'userName' => $target['userName'],
'orderID' => $target['orderID'],
]);
$emailRes = $email
->setFrom(['no-reply#service.com' => 'service announence'])
->setTo($target['email'])
->setSubject($subject)
->send();
if (!$emailRes) {
$res = false;
break;
}
}
Every mail sent is slightly different.
Is there a way to improve the mailing speed?
The speed of your mailing will be dictated by the speed of your configured transport (See https://book.cakephp.org/3/en/core-libraries/email.html#using-transports).
Sending the emails sequentially like this will always take time and it's normally done in some sort of background process (like a cron job).
If you really need to send emails quicker than what a quick transport can offer (for orders and other transactional email, I doubt it) you could investigate other options. Most email API services provide some sort of way to send bulk messages using templates (such as Sendgrid, Mandrill, Mailgun, Postmark, etc.)
I am using Laravel 5.5 and Mailgun. I want to send email campaigns to over 700 recipients and likely this list will grow into the thousands. Currently I am looping through each email address and sending the emails one at a time. As a result usually only about 530 emails go out. I have searched the net and cannot seem to find a good explanation on how to approach this in a more efficient way so that all the emails are sent. Any suggestions would be greatly appreciated.
public function mailCampaign()
{
//Code to get all email data in JSON
$emails= json_decode($data->getBody());
$baseUrl = config('constants.base_url');
foreach($emails as $key => $email){
Mail::to($email)
->send(new EmailInstance($variable, $email, $baseUrl));
}
$data = ['message' => 'Success. Emails have been sent.'];
return response()->view('emails.mail', $data, 200);
}
You shouldn't send emails one by one. Use Mailgun API instead. You can send thousands of emails using API with Bogardo/Mailgun package.
Mailgun supports the ability send to a group of recipients through a single API call. This is achieved by specifying multiple recipient email addresses as to parameters and using Recipient Variables.
I am creating a simple contact us form using Laravel 5.1
public function sendMessage(){
$data = [
'name' => Input::get('name'),
'email' => Input::get('email'),
'subject' => Input::get('subject'),
'body' => Input::get('body')
];
Mail::send('emails.contact',$data, function($message) use($data){
$message->from($data['email'], $data['name']);
$message->to('smartrahat#gmail.com','Mohammed');
$message->subject($data['subject']);
});
Session::flash('success_message','Mail sent successfully!');
return redirect('contact');
}
Everything is working fine but the sender email address is not the one it get from the contact page. The email is sent from the address which I configure in .env
I want to have the email from the sender email address which he filled up contact form. Or, you can say I want to change the header information (only from, I can change other information).
Well Laravel will send the mail through the given smtp server. I guess the smtp server (e.g. google doing this) will not let you change your from address to another address then the account belongs to.
If you want to reply to this address directly in your email programm you can add $message->replyTo($data['email'], $data['name']);.
The $message variable inside the Mail::send() function is a SwiftMailer message instance. Therefore, you can work with headers just like the SwiftMailer documentation shows. Just use $message->getSwiftMessage() to get and manipulate the headers.
Also, you absolutely can change the From header, but if you change it to a different domain, you'll have to deal with phishing warnings in the client. You can resolve that by setting up DKIM and SPF records, and you will need to have access to the DNS settings for the domain to do that.
I want to send an email to a list of address but I want each person to receive the email with his email address in to: (and not with the other email addresses of the diffusion list).
I am using symfony and Swift mail. My code look like that at the moment (it is working):
public function sendmail(Notification $notification, $alert){
$to = array();
foreach ($members as $member) {
$to[] = $member->getUser()->getEmail();
}
$html = $this->templating->render(
'PlatformBundle:Emails:email.html.twig',
array('alert' => $alert, 'notification' => $notification, 'user' => $this->user)
);
// Configure and send the mail
$message = \Swift_Message::newInstance()
->setSubject('an email ')
->setFrom($this->sender_email)
->setCc($this->user->getEmail())
->setTo($to)
->setBody($html, 'text/html');
$mailStatus = $this->mailer->send($message);
}
I have 2 solutions (I do not like any for them!).
using BCC (Sending to multiple Email addresses but displaying only one C#) but it makes my email looking like a spam
looping and sending the same email to each member (seems really server resource consuming)
public function sendmail(Notification $notification, $alert){
$to = array();
foreach ($members as $member) {
$to[] = $member->getUser()->getEmail();
$html = $this->templating->render(
'PlatformBundle:Emails:email.html.twig',
array('alert' => $alert, 'notification' => $notification, 'user' => $this->user)
);
// Configure and send the mail
$message = \Swift_Message::newInstance()
->setSubject('an email ')
->setFrom($this->sender_email)
->setCc($this->user->getEmail())
->setTo($to)
->setBody($html, 'text/html');
$mailStatus = $this->mailer->send($message);
}
Is this loop OK?
Any better idea?
Looping is really the only solution.
If you have many recipients, you will be marked as spam (and banned) pretty fast. You will want to go through a dedicated mail platform (with a bit of time between each send), which you can code yourself (pretty heavy work), or there are many mail platform as service around, like MailChimp or MailJet for instance.
It all depends on the number of mails to send. Up to about 100 per day might be OK (although it's an arbitrary number from the top of my head).
More than a certain threshold, and depending on the mail server you use (local on your server or gmail for instance), your IP or account might get banned. Most email providers have a mail limit per day, for instance.
Email services have many rules for sending, for instance, they delay the emails ; they send using multiple domains and addresses ; they work with the main mail providers (gmail, yahoo...) to make sure their domains are not marked as spam automatically...
Basically, if you really want to send many emails to many people, I really don't recommend doing it yourself. There are too many caveats.
I'm sending an email with some xheader.
When the recipient of the email replays to that email, i want to parse it, and get the content of that xheader from the mail i get by replay.
unfortunately, when i'm parsing the email i get back, i don't see my xheader.
(I printed the whole email, and the xheader is not there)
How can i do that in PHP with Zend Framework (i'm using Zend_Mail_Storage_Imap)?
Code:
$mail = new Zend_Mail_Storage_Imap(array(
'host' => 'pop.gmail.com',
'user' => 'a#gmail.com',
'password' => 'a',
'ssl' => 'SSL'
));
$count = $mail->countMessages();
$message = $mail->getMessage($count);
print_r($message);
//go through the message
foreach(new RecursiveIteratorIterator($message) as $part){
echo '*****************<br/>';
print_r($part);
echo '<br/>*****************<br/>';
//match parts content type to text/html - the one that maches is the message HTML body
if (preg_match('/.*text\/html.*/', $part->contentType)){
$body = $part->getContent();
}
$headers = $part->getHeaders();
if (isset($headers['X-aHeader'])){
echo $headers['X-aHeader'];
}
Thanks,
Boris.
Pekka gets points for the correct response here - X-headers in an original message will not necessarily be retained for any replies to that message. But, you're using Gmail, so you have another potential option.
Gmail allows plus addressing, so username#gmail.com will also receive mail for username+extra#gmail.com. If your X-aHeader content is alphanumeric, you can append it to your email address (e.g. a+headerdata#gmail.com). If your header content isn't alphanumeric, I'd recommend caching what you would put in the header locally on your system, and provide a uniqid as the email plus-address. When you receive a reply, you can use that uniqid to look up the data you cached locally.
This is a common technique for uniquely identifying recipients who reply to emails, or who perhaps bounce messages.