Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dariodiaz/8544119 to your computer and use it in GitHub Desktop.
Save dariodiaz/8544119 to your computer and use it in GitHub Desktop.
laravel: send emails with sendy
Setting up Sendy with Laravel
(there might be bugs, I striped out some parts of my code because what I have is more complicated then that, so, sorry if it's broken!)
--
I would recommand creating a database for Sendy only.
Add Sendy's database into your database.php (1)
Create the Campaign model (2), and specify that you want to use Sendy's database (Campaigns are the only thing we really need to create, other things like creating lists can be done through Sendy interface, and there is a PHP library to add subscribers)
Now, it's time to install Sendy, usually somewhere like yourapp.com/sendy or yourapp.com/newsletter
Following those instructions should do the trick : http://sendy.co/get-started
The Amazon part takes time. You will have to verify your domain and all. While you wait for your domain to authenticate, you can do the rest of the code (3, 4, 5, 6).
There would be a lot to say, but I think that my code will speak for itself. I have a lot of functions as I have multiple templates and that my app is bilingual, but that should help!
You have to setup cronjob for Sendy if you want to schedule your newsletter. Create a dummy newsletter form Sendy, then you will see the Schedule button and instructions about how to setup that!
If you want, I've included the code (7 and 8) so you can run "php artisan newsletter:generate" and tadam! You can also run a cronjob to trigger it, that's magic, I know. More on that here : http://stackoverflow.com/questions/16374513/cron-job-in-laravel
And if you want to read about the Sendy PHP Library used into SendyLibrary.php (5) : https://github.com/JacobBennett/SendyPHPLibrary
app/config/database.php
<?php
return array(
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'laravel',
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'newsletter' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'sendy',
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
)
);
app/model/campaign.php
<?php
class Campaign extends Eloquent {
protected $connection = 'newsletter';
public $timestamps = false;
}
app/Acme/Newsletter/Newsletter.php
<?php namespace Acme\Newsletter;
use App;
use View;
class Newsletter {
/**
* __construct
*
* Adding path to newsletters templates
*/
public function __construct()
{
View::addLocation(app('path').'/Acme/Newsletter/template');
View::addNamespace('NewsletterTemplate', app('path').'/Acme/Newsletter/template');
}
/**
* Generate the HTML output of a newsletter
*
* @return string
*/
public function generateHTML()
{
$_SERVER['HTTP_HOST'] = 'yourapp.com';
// Fetch your data, if it's dynamic
$data = Data::take(3)->get();
$title = "My newsletter, featuring " . $data->first()->title . " and more!";
$html = View::make('NewsletterTemplate::template')
->with('data',$data)
->render();
return array("html" => $html, "title" => $title);
}
/**
* Generate the newsletter
*
* @return str
*/
public function generate(){
if( (new \Acme\Newsletter\Sendy)->create() ){
return "SUCCESS";
}
return "FAIL";
}
app/Acme/Newsletter/Sendy.php
<?php namespace Acme\Newsletter;
use App;
use Campaign;
use Carbon;
class Sendy extends Newsletter {
// The id and key of your list can be found once you created a new list through Sendy. Each list has a custom "key" (like : fsakjbfa2r3tg) and id (like : 1) If you have multiple lists, you could use an array or fetch it from Sendy database.
private $list_id = array(1 => "rbcNeGuRfff4e0sDJds5brQ");
/**
* Subscribe a user to a list
*
* @param string $email
*
* @return string
*/
public function subscribe($email){
$sendy = new SendyLibrary($this->list_id[1]);
$result = $sendy->subscribe(array(
'email' => $email
));
return $result['message'];
}
/**
* A user can usubscribe from a list following the link generated with the <unsubscribe> tag into a newsletter
/**
* Create the campaign
*
* @return bool
*/
public function create()
{
$data = $this->generateHTML();
$campaign = new Campaign();
$campaign->userID = 1;
$campaign->app = 1;
$campaign->from_name = "Your name";
$campaign->from_email = "no-reply@yourapp.com";
$campaign->reply_to = "no-reply@yourapp.com";
$campaign->title = $data['title'];
$campaign->html_text = $data['html'];
$campaign->wysiwyg = 0;
// Use your timezone!
$campaign->timezone = "America/Montreal";
// You can target multiple lists with an array of ids, like array(1,3,7)
$campaign->lists = 1;
// That will schedule your newsletter to send in 5mn, so you can have a quick look before it goes live
$campaign->send_date = Carbon::now()->addMinutes(5)->timestamp;
if($campaign->save()){
return true;
}
return false;
}
}
app/Acme/Newsletter/SendyLibrary.php
<?php
namespace Acme\Newsletter;
class SendyLibrary
{
private $installation_url = 'http://yourapp.com/sendy';
private $api_key = 'your_api_key';
private $list_id;
function __construct($list_id)
{
//error checking
if (!isset($list_id)) {throw new Exception("Required config parameter [list_id] is not set", 1);}
if (!isset($this->installation_url)) {throw new Exception("Required config parameter [installation_url] is not set", 1);}
if (!isset($this->api_key)) {throw new Exception("Required config parameter [api_key] is not set", 1);}
$this->list_id = $list_id;
}
public function subscribe(array $values) {
$type = 'subscribe';
//Send the subscribe
$result = strval($this->buildAndSend($type, $values));
//Handle results
switch ($result) {
case '1':
return array(
'status' => true,
'message' => 'Subscribed'
);
break;
case 'Already subscribed.':
return array(
'status' => true,
'message' => 'Already subscribed.'
);
break;
default:
return array(
'status' => false,
'message' => $result
);
break;
}
}
public function unsubscribe($email) {
$type = 'unsubscribe';
//Send the unsubscribe
$result = strval($this->buildAndSend($type, array('email' => $email)));
//Handle results
switch ($result) {
case '1':
return array(
'status' => true,
'message' => 'Unsubscribed'
);
break;
default:
return array(
'status' => false,
'message' => $result
);
break;
}
}
public function substatus($email) {
$type = 'api/subscribers/subscription-status.php';
//Send the request for status
$result = $this->buildAndSend($type, array('email' => $email, 'api_key' => $this->api_key, 'list_id' => $this->list_id));
//Handle the results
switch ($result) {
case 'Subscribed':
case 'Unsubscribed':
case 'Unconfirmed':
case 'Bounced':
case 'Soft bounced':
case 'Complained':
return array(
'status' => true,
'message' => $result
);
break;
default:
return array(
'status' => false,
'message' => $result
);
break;
}
}
public function subcount($list = "") {
$type = 'api/subscribers/active-subscriber-count.php';
//handle exceptions
if($list== "" && $this->list_id == "") {throw new Exception("method [subcount] requires parameter [list] or [$this->list_id] to be set.", 1);}
//if a list is passed in use it, otherwise use $this->list_id
if($list == "") {$list = $this->list_id;}
//Send request for subcount
$result = $this->buildAndSend($type, array('api_key' => $this->api_key, 'list_id' => $list));
//Handle the results
if (is_int($result)) {
return array(
'status' => true,
'message' => $result
);
}
//Error
return array(
'status' => false,
'message' => $result
);
}
private function buildAndSend($type, array $values) {
//error checking
if (!isset($type)) {throw new Exception("Required config parameter [type] is not set", 1);}
if (!isset($values)) {throw new Exception("Required config parameter [values] is not set", 1);}
//Global options for return
$return_options = array(
'list' => $this->list_id,
'boolean' => 'true'
);
//Merge the passed in values with the options for return
$content = array_merge($values, $return_options);
//build a query using the $content
$postdata = http_build_query($content);
$opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata));
$context = stream_context_create($opts);
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //Set curl to return the data instead of printing it to the browser.
curl_setopt($ch, CURLOPT_URL, $this->installation_url .'/'. $type);
$data = curl_exec($ch);
curl_close($ch);
return $data;
$result = file_get_contents($this->installation_url .'/'. $type, false, $context);
return $result;
}
/**
* Magic methods below
* http://www.php.net/manual/en/language.oop5.overloading.php
*/
public function __get($property) {
if (property_exists($this, $property)) {
return $this->$property;
}
}
public function __set($property, $value) {
if (property_exists($this, $property)) {
$this->$property = $value;
}
return $this;
}
}
?>
app/Acme/Newsletter/template/template.blade.php
I'd recommand starting with http://zurb.com/playground/responsive-email-templates or http://zurb.com/ink/
Create your HTML page that will be send as your newsletter!
app/commands/GenerateNewsletter.php
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Acme\Newsletter\Newsletter;
use Acme\Newsletter\Sendy;
class GenerateNewsletter extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'newsletter:generate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generating the newsletter';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$execute = (new \Acme\Newsletter\Sendy)->generate();
$this->info($execute);
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
}
}
app/start/artisan.php
<?php
Artisan::add(new GenerateNewsletter);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment