Your question is split up into two chunks:
- How do I get my list of emails out of MailChimp?
- How can I send emails to arbitrary email addresses?
The first chunk is the most important here. The second chunk has a ton of possible answers and should be fairly easy to accomplish.
Getting the list from MailChimp
MailChimp provides an API that is critical. Currently, they are working on v3.0, but v2.0 is still marked as 'current', so we will be relying on that version of the API. To use the API, MailChimp recommends a few third-party packages. For this example, I am using mailchimp-api which can be installed using composer:
$ composer require drewm/mailchimp-api
To authenticate yourself to MailChimp, you will need an API key. MailChimp provides full instructions to get the API key, but the short version is this:
Click your profile name to expand the Account Panel, and choose
Account.
Click the Extras drop-down menu and choose API keys.
Copy an existing API key or click the Create A Key button.
Name your key descriptively, so you know what application uses that
key.
Next, you need your list id for the list you want to grab emails from. Once again, MailChimp provides the best documentation for this. My list id was a string of 10 characters containing both letters and numbers.
Finally, we write the PHP:
$apiKey = /*Your API key*/;
$listId = /*Your List ID*/;
$MailChimp = new \Drewm\MailChimp($apiKey);
$args = array(
'id' => $listId,
);
$result = $MailChimp->call('lists/members', $args);
//Check for any errors first, if none have occured, build the email list.
if(isset($result['status']) && $result['status'] == 'error'){
throw new Exception('call to Mailchimp API has failed.');
} else {
$emails = array();
//Build an array of emails for users that are currently subscribed.
foreach($result['data'] as $recipient){
if($recipient['status'] == 'subscribed' && !empty($recipient['email'])){
$emails[] = $recipient['email'];
}
}
}
$MailChimp->call('lists/members', $args)
returns a very hefty JSON response with lots of interesting information. If you were storing personalized information via merge settings in MailChimp, they will be available in this JSON response. However, to keep this example as simple as possible, I've only checked if a user is subscribed and stored their email address.
At the end of this block, $emails
now store all of the email address in your list. Since this calls the API each time, anyone who unsubscribes from your mailing list on MailChimp will be removed here as well.
A possible gotcha may occur during this stage. If you have a large list (I tested with only 4), you may run into a memory issue where PHP tries to build a huge $emails
array. If you run into this problem, you should chunk out reading emails in smaller blocks and send emails like that.
Sending bulk email using PHP
Others have recommended using Mandrill to send out bulk email. This is bad idea. Mandrill is the sister service to MailChimp that is intended to send out transactional email - MailChimp is intended for bulk email (like a newsletter).
There are tons of ways to send out emails using PHP, I'm opting to use Sendgrid as my SMTP provider and SwiftMailer to connect to it. Other alternatives would be to use PHP's mail()
function or a different library like PHPMailer.
You can install SwiftMailer using Composer:
$ composer require swiftmailer/swiftmailer @stable
I go into more detail about SwiftMailer and SMTP services (though in slightly different context) in this question. But this example will do what it needs to.
$sendgridUser = /*SendGridUsername*/;
$sendgridPassword = /*SendGridPassword*/;
$subject = "Thank you for using MailChimp Lists!";
$fromAddress = "HPierce@example.com";
$fromName = "Hayden Pierce";
$body = file_get_contents(/*path to content (body.html)*/);
$transport = Swift_SmtpTransport::newInstance('smtp.sendgrid.net', 587, 'tls')
->setUsername($sendgridUser)
->setPassword($sendgridPassword)
;
foreach($emails as $email){
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance()
->setSubject($subject)
->setFrom(array($fromAddress => $fromName))
->setTo($email)
->setBody($body);
$mailer->send($message);
exit();
}
For simplicity's sake, I've read the entire body from a static HTML file. You may consider using a template engine like Twig to better implement it using templates.
All this code put together looks like this:
//Loading in composer dependencies
require "vendor/autoload.php";
//Provided by Mailchimp account settings
$apiKey = /*MailChimp API keys*/;
$listId = /*MailChimp List id*/;
$sendgridUser = /*SendGridUser*/;
$sendgridPassword = /*SendGridPassword*/;
$subject = /*The subject line of your email*/;
$fromAddress = /*The email address for your FROM line*/;
$fromName = /*The name in your FROM line*/;
$body = file_get_contents(/*path to your html content*/);
$MailChimp = new \Drewm\MailChimp($apiKey);
$args = array(
'id' => $listId,
);
$result = $MailChimp->call('lists/members', $args);
//Check for any errors first, if none have occurred, build the email list.
if(isset($result['status']) && $result['status'] == 'error'){
throw new Exception('call to Mailchimp API has failed.');
} else {
$emails = array();
//Build an array of emails for users that are currently subscribed.
foreach($result['data'] as $recipient){
if($recipient['status'] == 'subscribed' && !empty($recipient['email'])){
$emails[] = $recipient['email'];
}
}
}
//Setup for sending emails to an arbitrary list of emails using Sendgrid.
$transport = Swift_SmtpTransport::newInstance('smtp.sendgrid.net', 587, 'tls')
->setUsername($sendgridUser)
->setPassword($sendgridPassword)
;
foreach($emails as $email){
//Send emails to each user.
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance()
->setSubject($subject)
->setFrom(array($fromAddress => $fromName))
->setTo($email)
->setBody($body);
$mailer->send($message);
}