Open-source mailing list applet using the Mailgun PHP SDK

This post was written by Jeff Reifman, a Seattle-based technology consultant and founder of Geogram, a free group email service for local places powered by Mailgun. Follow him at @reifman.

Introduction to Mailgun Lists

While Mailgun is primarily known as a scalable cloud-blased email engine, its mailing list functionality provides an easy and convenient way to manage lists and broadcast messages to multiple recipients. You can send messages to Mailgun's mailing lists via your favorite web email provider, email client, smartphone or via the API. And, Mailgun provides API's for programmatically managing and sending to your lists. Recently, Mailgun released a new SDK for PHP to make using its API even easier.

You might find Mailgun's mailing lists provide the core functionality you need to move away from paid email services or open source list applications such as PHPList. I use Mailgun's list services to communicate with friends, reach out to my social communities and for business outreach.

Not only does this tutorial describe how to use the Mailgun Mailing List API to manage your own lists via PHP but it provides free, open source, installable source code for a small web-based application, ListApp, that allows you to manage and send emails via the List API using Mailgun.com. It's primarily meant to demonstrate how you might use the Mailgun List API in your application. ListApp is written in the Yii Framework for PHP. You don't need to know anything about the Yii framework to run the application.

ListApp login and home page

How to install and use the open source application

The application provides a simple web-based front end to common scenarios you might use with Mailgun's mailing list features:

  • Synchronizing your lists and list members
  • Creating, updating and deleting lists
  • Importing members to a list
  • Sending messages to lists
  • Providing a public subscription form with Mailgun's new email validation service

View your mailing lists

Manage your list - detail view

The code for ListApp is freely available on Github.com. You can install it on any PHP/MySQL server. I've included instructions for setting up ListApp on a Rackspace Cloud Ubuntu 12.04 server with 1 GB RAM. We use Ubuntu Linux, Apache, PHP 5.x, MySQL 5.x, PEAR and cURL libraries.

Even if you use your own server, you should read the Rackspace setup instructions for creating an apache site, creating and installing the database and generating your login credentials. It's also important to customize your site settings in the config-listapp.ini file.

You'll need to sign up for a free (or higher level) Mailgun account in order to get your API keys for the settings file. If you have a paid account, you'll need to add your domains and create DNS settings for using them. If you use a free account, your domain will be yourchoice.mailgun.org. Therefore, your list addresses can be wildcard@yourchoice.mailgun.org. Your Mailgun API keys will be shown on the control panel home page.

How to use the Mailgun Mailing List API

Using the Mailgun Mailing List API is very straightforward. Mailgun provides its own Mailing List API documentation to assist us. You can review how ListApp uses the Mailgun API in our Yiigun.php component. ListApp uses the Mailgun PHP SDK to interact with Mailgun.

Here are some examples for common uses of the mailing list API with Mailgun:

Initializing the Mailgun PHP SDK

Whenever the Yiigun class is used, the constructor is called creating a secure initialization with Mailgun's API:

function __construct() {  
     // initialize mailgun connection
     $this->mg = new Mailgun(Yii::app()->params['mailgun']['api_key']);
}

Synchronizing lists and list members

Once you login into ListApp, click on the Synchronize option. This will fetch copies of all the existing mailing lists at Mailgun and download all their members into the local database. It essentially, synchronizes down your mailing list from the Mailgun.com site. This option does not synchronize up.

Here's the fetchLists function. Using the Mailgun PHP SDK makes this quite simple:

  public function fetchLists() {  
    $result = $this->mg->get("lists");
    return $result->http_response_body;    
  }

Here's how we fetch members:

  public function fetchListMembers($address) {  
    $result = $this->mg->get("lists/".$address.'/members');
    return $result->http_response_body;    
  }

Creating a list

You can create new mailing lists by using the menu options on the right of ListApp. Each list requires a name, list email address and description. When you create a new list, ListApp uploads the list and its settings to Mailgun.com as well. You can also update the properties for any list.

Here's how we create a new list:

public function listCreate($newlist) {  
    $result = $this->mg->post("lists",array('address'=>$newlist->address,'name'=>$newlist->name,'description' => $newlist->description,'access_level' => $newlist->access_level));
    return $result->http_response_body;    
  }

Here's how we update mailing list properties:

  public function listUpdate($existing_address,$model) {  
    $result = $this->mg->put("lists/".$existing_address,array(
      'address'=>$model->address,
      'name' => $model->name,
      'description' => $model->description,
      'access_level' => $model->access_level
      ));
    return $result->http_response_body;    
   }

Importing members to the list

You can import new members to any list from ListApp. We use PEAR's email list parsing libraries for this feature. You can paste in any list of email addresses in the form Personal Name <mailbox@domain.com> separate by commas or newlines. ListApp will add the members locally and upload them to Mailgun.com.

To add members by bulk, first we create a JSON string of the new members to upload ... here's some sample code that you might use. You can see a complete example here.

$json_upload ='['  
 foreach ($addresses as $i) {
  $json_upload.='{';
    $json_upload.='"name": "'.$i->name.'", ';                  
    $json_upload.='"address": "'.$i->address.'"';                  
    $json_upload.='},';            
  }
$json_upload.=']';

Then, we call the bulk upload function with this JSON string:

   public function memberBulkAdd($list='',$json_str='') {  
     $result = $this->mg->post("lists/".$list.'/members.json',array(
    'members' => $json_str,
     'subscribed' => true,
     'upsert' => 'yes'
     ));
     return $result->http_response_body;    
   }

You can add individual members to lists as well using the Add a Member menu option.

Sending a message

You can send a message to any list using the menu on the right. We deliver the outbound message to Mailgun like any other message:

public function send_simple_message($to='',$subject='',$body='',$from='') {  
    if ($from == '') 
      $from = Yii::app()->params['supportEmail'];
    $domain = Yii::app()->params['mail_domain'];
$result = $this->mg->sendMessage($domain,array('from' => $from, 'to' => $to, 'subject' => $subject, 'text' => $body, )); 
return $result->http_response_body;  
}

Mailgun will then manage the delivery of the message to individual recipients.

You can also use some of the generic Mailgun recipient variables to include personal salutations, such as Hi %recipient_fname% (see Template Variables).

Using the Public Subscribe Form

You can View the Subscribe form from the ListApp list detail page. And, you can link users to the public subscription form for a list at http://listapp.yourdomain.com/request/create/<list-id#>;:

ListApp subscribe form

ListApp also makes use of Mailgun's new Email Validation API which detects typos such as @gmal.com:

Mailgun Email Validation

We're using Yii's built in AJAX validation to integrate Mailgun's Email Verification API. Yii's rule function calls a custom validator we've built that speaks to the Mailgun Validator - see Request model:

    public function rules()  
    {
        return array(
            array('address', 'required'),
            array('name, address', 'length', 'max'=>255),
            array('address', 'mailgunValidator'),
        );
    }

  public function mailgunValidator($attribute,$params)
  {
        $yg = new Yiigun();
           $result = $yg->validate($this->$attribute);
           if ($result->is_valid)
             return false;
           else {
          $this->addError($attribute, 'There is a problem with your email address '.$result->address.'. Did you mean '.$result->did_you_mean.'?');             
           }
  }

   function validate($email='') {
     $this->mgValidate = new Mailgun(Yii::app()->params['mailgun']['public_key']);
     $result = $this->mgValidate->get('address/validate', array('address' => $email));
    return $result->http_response_body;
   }

Once a subscription request is validated, we use the Mailgun SDK Opt In Handler to email the user with a verification link; this prevents false adds:

   public function generateVerifyHash($model,$mglist) {  
     // generate secure hash for verifying subscription requests
     $verify_secret = Yii::app()->params['verify_secret'];
     $optInHandler = $this->mg->OptInHandler();
     $generatedHash = $optInHandler->generateHash($mglist->address, $verify_secret, $model->address);
     // remove encodings - fixes yii routing issue
     $generatedHash = str_ireplace('%','',$generatedHash);
     return $generatedHash;
   }

   public function sendVerificationRequest($model,$mglist) {
     // send an email with the verification link 
          $body="Please verify your subscription by clicking on the link below:\r\n".Yii::app()->getBaseUrl(true)."/request/verify/".$model->id."/".$model->hash;
          $this->send_simple_message($model->address,'Please verify your subscription to '.$mglist->name,$body,Yii::app()->params['support_email']);
   }

Here is how we add subscribed members when they click the verification link - in the RequestController:

public function actionVerify($id,$hash)  
    {
      $request = $this->loadModel($id);
      if ($hash==$request->hash) {
      $mglist = Mglist::model()->findByPk($request->mglist_id);
      // insert new Member
      $member_id=$request->insertMember($request->name,$request->address);
      // add member to this list
      Member::model()->addToList($member_id,$request->mglist_id);
      // add member at Mailgun
          $yg = new Yiigun();
          $yg->memberAdd($mglist->address,$request->address,$request->name);      
          $this->render('verify',array(
              'model'=>$this->loadModel($id),
              'mglist'=>$mglist,
          ));
      } else {
        echo 'Sorry, your request is invalid.';
        yexit();
      }
    }

  public function memberAdd($list='',$email='',$name='') {
    $result = $this->mg->post("lists/".$list.'/members',array('address'=>$email,'name'=>$name,'subscribed' => true,'upsert' => 'yes'));
    return $result->http_response_body;    
  }

Adopting this code for PHP (not Yii)

Yii is essentially an MVC framework like Ruby on Rails, but with all the simplicity and maturity of PHP. It’s fast, efficient and relatively straightforward. It also includes scaffolding/code generation, active record, transaction support, I18n localization, caching support et al. The documentation, community support and available plugins are also quite good. It took less than 10 hours using Yii to build ListApp.

However, if you prefer not to use Yii, you can build on the Yiigun component used in ListApp. Yiigun.php is essentially a PHP class file with methods and helpers for leveraging the Mailgun Mailing List SDK.

The current version of ListApp talks to Mailgun in real time and does not have extensive error handling. Longer term, it would be good to add asynchronous, queued API requests.

In addition to Mailgun's own Mailing List API documentation (which includes examples in cURL, Ruby, PHP, Python, Java and C#), you can review, extract and adapt the Yiigun.php file and its functions for your own PHP application or framework.

If you don't use Yii, you'll need to use composer to install the SDK per Mailgun's installation instructions.

How to contribute to extensions for the open source application via Github

If you'd like to add features or extend ListApp for your own purposes, I suggest that you fork the code on Github. If we issue any updates or new features, you can merge the changes into your work at any time.

If you'd like to contribute to ListApp by adding features and asking us to include them in the main codebase (we'd love that), you can submit a pull request.

Git is an extremely powerful Internet-based, collaborative source code management tool - but it can be a bit confusing to get started with. Check out their help page for guides to common usages.

Related Links

comments powered by Disqus

Mailgun Get posts by email

Like what you're reading? Get these posts delivered to your inbox.

No spam, ever.