LARAVEL PACKAGE: MAILCHIMP API INTEGRATION

Subscribe New Users to MailChimp List

August 13th, 2019 by Kevin Pimentel

My blog, kevinpimentel.com, has a subscription form that I want to connect to MailChimp. I could probably get a Laravel MailChimp package if I Googled one, but that’s not going to help me sharpen my Laravel skills. I’ve decided to write my own MailChimp subscription package for Laravel. 


The package should have a config file that grabs an API key from the Laravel environment file. In a future iteration, we could make it so that the member list API key is inserted through settings. 


This will make selecting a list more dynamic. For now, a configuration file will get the job done. To get started, I am going to create a MailChimp account and get myself an API key.


I’ll then setup the basic package structure which I have already done here. This package will include a config file that will be publishable via php artisan.


LazyElePHPant / laravel-mailchimp



Testing Environment


In my local Laravel development environment I will configure the composer.json file in my blog codebase as follows:


Required


"lazyelephpant/mailchimp": "dev-master"


Repositories


"repositories":[
    {
        "type":"path",
        "url":"../LazyElePHPant/mailchimp",
        "options":{
            "symlink":true
        }
    }
],


This configuration will enable me to receive immediate feedback.


The end goal is to be able to call subscribe on an email.


$mailchimp->subscribe($email);


The API should be as simple as possible to use.


Package Config


I’ll start by setting up the package configuration. We need to accept an api key and a list id. Making the list id dynamic is a good idea but I only require one list for my subscription form. The API URL I’ll discuss in the comments below.


<?php

return [
	/*
    |----------------------------------------------------------------
    | MailChimp API URL
    |----------------------------------------------------------------
    |
    | Here you may specify the mailchimp API URL. You need to look at your account to 
    | determine the correct datacenter. https://<dc>.api.mailchimp.com/3.0
    | The <dc> part will correspond to your account URL. Simply look at the URL when you
	| are logged in and that should tell you the correct value for <dc>.
    | https://developer.mailchimp.com/documentation/mailchimp/guides/get-started-with-mailchimp-api-3/
    |
    */

    'mailchimp_api_url' => env('MAILCHIMP_API_URL', null),
    
    /*
    |----------------------------------------------------------------
    | MailChimp API Key
    |----------------------------------------------------------------
    |
    | Here you may specify the mailchimp key for the account that you wish to access
    | https://createform.com/support/mailchimp-api
    |
    */

    'mailchimp_api_key' => env('MAILCHIMP_API_KEY', null),

    /*
    |----------------------------------------------------------------
    | List ID
    |----------------------------------------------------------------
    |
    | Here you may specify a default list id.
    |
    */

    'mailchimp_list_id' => env('MAILCHIMP_LIST_ID', null),

    /*
    |--------------------------------------------------------------------------
    | Username
    |--------------------------------------------------------------------------
    |
    | Here you may specify the account username.
    |
    */

    'username' => env('MAILCHIMP_USERNAME', null),
];


In my service provider I’ll make the mailchimp.php config file publishable. 


<?php

namespace LazyElePHPant\MailChimp;

use Illuminate\Support\ServiceProvider;

class MailChimpServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        $this->publishes([
            __DIR__.'/config/mailchimp.php' => config_path('mailchimp.php')
        ], ‘mailchimp’);
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {

    }
}


In the main application we will be able to run the vendor:publish artisan command to import the mailchimp.php config file into our config folder.


Guzzle


We then composer require THE Guzzle.


$ composer require guzzlehttp/guzzle


We should only have guzzle and phpunit installed.


Main Application


In the main application I’ll run composer update to get the latest from the package.


$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 1 removal
  - Removing junction for lazyelephpant/mypackage (dev-master)
  - Installing lazyelephpant/mailchimp (dev-master): Junctioning from ../lazyele
phpant/mailchimp
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: lazyelephpant/mailchimp
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.


In the main application, I’ll run the vendor:publish command to pull in the mailchimp configuration file from our package.


$ php artisan vendor:publish --tag=mailchimp


Next, I’ll configure my keys in the environment file.



In my main application I have a method store that gets called when a user subscribes. There’s email validation happening to make sure the email is unique. After, there’s reCaptcha v3 validation to make sure the spam score is acceptable. If both checks pass I create a record in the database. I want to now add code to subscribe the user to MailChimp if everything is successful.


public function store(SubscriberRequest $request)
{    
    if (!$this->isValidCaptcha($request->all())) {
         return redirect()->back()->withErrors([
	       'message' => 'invalid recaptcha'
	    ]);
    }

	if (Subscriber::create($request->validated())) {
	    optional($this->mailchimp)->subscribe($request->email);

     	    return redirect()
              ->back()
              ->with('message', 'subscribed successfully!');
	}

	abort(503);
}


In our MailChimp Laravel Package we want to handle the subscription of an email. 


public function subscribe(string $email = '')
{
	$list_id = config('mailchimp.list_id');

	if (is_null($list_id) || empty($email)) return false;

 	return $this->call('POST', "/3.0/lists/{$list_id}/members/", [
 		'email_address' => $email,
 		'status' => 'subscribed'
	]);
}


The ListMember subscribe method accepts a string parameter, email. If the parameter is empty or there is no list id defined then we will return false and the email will not get subscribed to mailchimp. However, if the email is not empty and a list id is not null we call the call method.


public function call(string $method, string $path, array $params = [])
{
	if (is_null(config('mailchimp.username')) ||                           
         is_null(config('mailchimp.api_key'))) return false;

	try {
		return $this->client->request('POST', $path, [
			'auth' => [
				config('mailchimp.username'),
				config('mailchimp.api_key')
			],
			'json' =>  $params
		]);
	} catch(Exception $e) {
		return $e->getMessage();
	}
}


The call method checks for username and an api key. If both are defined we sent a POST request to MailChimp with our username, api key, and the email we are trying to subscribe.




Conclusion


The process for creating an integration with most email service providers should be pretty similar. If needed, you can also pass additional fields. In the future we can modify the package to accept additional fields and be more robust. For more details on other types of fields that are acceptable click here.


LazyElePHPant / laravel-mailchimp


Kevin Pimentel

There are two types of people in the world: those that code, and those that don’t. I said that! Quote me. My name is Kevin and I’m one of the ones that codes.