Skip to content

Commit

Permalink
Cutover to Amazon SES for email sending. Goodbye postfix
Browse files Browse the repository at this point in the history
  • Loading branch information
katzgrau committed Dec 31, 2011
1 parent ec0fada commit 22d6e26
Show file tree
Hide file tree
Showing 21 changed files with 1,244 additions and 4 deletions.
2 changes: 1 addition & 1 deletion application/config/application.php
Expand Up @@ -28,7 +28,7 @@
$config['archive_path'] = 'static/archives/';

# Where to send system alerts
$config['system_alert_email'] = 'cron@oconf.org';
$config['system_alert_email'] = 'ohcrap@getsparks.org';

# The place to email when shit goes wrong
$config['support_email'] = 'ohcrap@getsparks.org';
Expand Down
3 changes: 3 additions & 0 deletions application/config/config.php
Expand Up @@ -6,6 +6,9 @@
# Use prod settings? (Super-caching, minifying, etc)
$config['is_production'] = FALSE;

# Environment-specific for SES. Required for mailing.
$config['ses_secret_key'] = '';
$config['ses_access_key'] = '';
/*
|--------------------------------------------------------------------------
| Base Site URL
Expand Down
73 changes: 73 additions & 0 deletions application/helpers/mailer_helper.php
@@ -0,0 +1,73 @@
<?php
/**
* This file contains a class for mailing GetSparks notifications
*/

/**
* A helper class for mailing things to Getsparks users
*/
class MailerHelper
{
/**
* Send a spark rejection email (when an invalid spark is submitted)
*/
public static function sendSparkRejection($to, $spark_name, $message)
{
$CI = &get_instance();
$sys_email = config_item('system_alert_email');
$subject = $spark_name.' Removed';
$content = $CI->load->view('email/spark_rejected', array('title' => $subject,
'teaser' => 'Puts up a brick! Your spark submission couldn\'t be verified',
'body' => nl2br($message)),
true);

self::sendEmail($to, $subject, $content, $message, array('cc' => $sys_email));
}

/**
* Send a generic email without a fancy footer and header
* @param string $to
* @param string $subject
* @param string $body
* @param string $teaser Optional. Appears as a teaser in some email clients
*/
public static function sendEmail($to, $subject, $content, $alt = false, $options = array())
{
$CI = &get_instance();
$CI->load->spark('amazon-ses/0.3.0');

# Main recipient
if(is_array($to))
{
foreach($to as $addr)

This comment has been minimized.

Copy link
@joelcox

joelcox Feb 23, 2012

Contributor

You can just pass the addresses as an array (or comma-separated list), the library will take care of this.

$CI->amazon_ses->to($addr);
}
else
{
$CI->amazon_ses->to($to);
}

# CCs
if(isset($options['cc']))
{
$cc = $options['cc'];
if(is_array($cc))
{
foreach($cc as $addr)
$CI->amazon_ses->cc($addr);

This comment has been minimized.

Copy link
@joelcox

joelcox Feb 23, 2012

Contributor

Ditto.

}
else
{
$CI->amazon_ses->cc($cc);
}
}

$CI->amazon_ses->subject($subject);
$CI->amazon_ses->message($content);

if($alt)
$CI->amazon_ses->message_alt($alt);

$CI->amazon_ses->send();
}
}
8 changes: 5 additions & 3 deletions application/models/spark.php
Expand Up @@ -390,21 +390,23 @@ public function setVersionStatus($version, $deactivated = FALSE)
*/
public function removeTagAndNotify($tag, $errors)
{
$this->load->helper('email');
$this->load->helper('mailer');
$contrib = $this->getContributor();
$sys_email = config_item('system_alert_email');

$message = "Hey there,
This is an automated message to tell you that tag '$tag' of
$this->name couldn't be verified ($this->base_location).
We've removed that version from our system at getsparks. Once you get
things figured out on your end, you can re-add the version :).
things figured out on your end, you can re-add the version :)
Here are some specifics: \n\n";

foreach($errors as $error)
$message .= "$error\n";

send_email("{$contrib->email},{$sys_email}", "{$this->name} {$tag} Removed.", $message);
MailerHelper::sendSparkRejection($contrib->email, "{$this->name} {$tag}", $message);

$this->db->where('spark_id', $this->id);
$this->db->where('tag', $tag);
Expand Down
26 changes: 26 additions & 0 deletions application/views/email/global/_footer.php
@@ -0,0 +1,26 @@

</div>
</td>
</tr></table><!-- // End Module: Standard Content \\ --></td>
</tr></table><!-- // End Template Body \\ --></td>
</tr><tr><td align="center" valign="top" style="border-collapse: collapse">
<!-- // Begin Template Footer \\ -->
<table border="0" cellpadding="10" cellspacing="0" width="600" id="templateFooter" style="background-color: #FFF;border-top: 0"><tr><td valign="top" class="footerContent" style="border-collapse: collapse">
<!-- // Begin Module: Standard Footer \\ -->
<table border="0" cellpadding="10" cellspacing="0" width="100%"><tr><td colspan="2" valign="middle" id="social" style="border-collapse: collapse;background-color: #FAFAFA;border: 0">
<div mc:edit="std_social" style="color: #707070;font-family: Arial;font-size: 12px;line-height: 125%;text-align: center">
<a href="http://twitter.com/getsparks">follow on Twitter</a> | <a href="https://www.facebook.com/getsparks">like on Facebook</a> | <a href="mailto:ohcrap@getsparks.org">tell someone who cares</a>
</div>
</td>
</tr><tr><td valign="top" width="350" style="border-collapse: collapse">
<div mc:edit="std_footer" style="color: #707070;font-family: Arial;font-size: 12px;line-height: 125%;text-align: left">
<em>Copyright © 2011 GetSparks.org, All rights reserved.</em>
</div>
</td>
</tr></table><!-- // End Module: Standard Footer \\ --></td>
</tr></table><!-- // End Template Footer \\ --></td>
</tr></table><br /></td>
</tr></table></center>
</body>
</html>
39 changes: 39 additions & 0 deletions application/views/email/global/_header.php
@@ -0,0 +1,39 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0" style="width: 100% !important;-webkit-text-size-adjust: none;margin: 0;padding: 0;background-color: #f0f0f0">
<center>
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%" id="backgroundTable" style="height: 100% !important;margin: 0;padding: 0;width: 100% !important;background-color: #f0f0f0"><tr><td align="center" valign="top" style="border-collapse: collapse">
<!-- // Begin Template Preheader \\ -->
<table border="0" cellpadding="10" cellspacing="0" width="600" id="templatePreheader" style="background-color: #272727"><tr><td valign="top" class="preheaderContent" style="border-collapse: collapse">

<!-- // Begin Module: Standard Preheader \ -->
<table border="0" cellpadding="10" cellspacing="0" width="100%"><tr><td valign="top" style="border-collapse: collapse">
<div mc:edit="std_preheader_content" style="color: #505050;font-family: Arial;font-size: 10px;line-height: 100%;text-align: left">
<?php echo $teaser ?> </div>
</td>
<!-- *|IFNOT:ARCHIVE_PAGE|* -->
<td valign="top" width="190" style="border-collapse: collapse">
<div mc:edit="std_preheader_links" style="color: #505050;font-family: Arial;font-size: 10px;line-height: 100%;text-align: left">
Code less, drink more.
</div>
</td>
<!-- *|END:IF|* -->
</tr></table><!-- // End Module: Standard Preheader \ --></td>
</tr></table><!-- // End Template Preheader \\ --><table border="0" cellpadding="0" cellspacing="0" width="600" id="templateContainer" style="border: 1px solid #DDD;background-color: #f9f9f9"><tr><td align="center" valign="top" style="border-collapse: collapse">
<!-- // Begin Template Header \\ -->
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateHeader" style="background-color: #333;border-bottom: 0"><tr><td class="headerContent" style="padding: 20px 10px 20px 10px;color: white;font-family: 'Trebuchet MS', Arial, serif;text-align: left;border-collapse: collapse;font-size: 27px;font-weight: bold;line-height: 100%;vertical-align: middle">

<!-- // Begin Module: Standard Header Image \\ -->
<!-- <img src="http://gallery.mailchimp.com/653153ae841fd11de66ad181a/images/placeholder_600.gif" style="max-width:600px;" id="headerImage campaign-icon" mc:label="header_image" mc:edit="header_image" mc:allowdesigner mc:allowtext /> -->
<!-- // End Module: Standard Header Image \\ -->
<img src="http://getsparks.org/static/images/sparks-logo-square-small.png" alt="GetSparks" style="border: 0;height: auto;line-height: 100%;outline: none;text-decoration: none" />
GetSparks Notification
</td>
</tr></table><!-- // End Template Header \\ --></td>
</tr><tr><td align="center" valign="top" style="border-collapse: collapse">
<!-- // Begin Template Body \\ -->
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateBody"><tr><td valign="top" class="bodyContent" style="border-collapse: collapse;background-color: #f9f9f9">

<!-- // Begin Module: Standard Content \\ -->
<table border="0" cellpadding="20" cellspacing="0" width="100%"><tr><td valign="top" style="border-collapse: collapse">
<div mc:edit="std_content00" style="color: #505050;font-family: Arial;font-size: 14px;line-height: 150%;text-align: left">
<h4 class="h4" style="color: #202020;display: block;font-family: Arial;font-size: 22px;font-weight: bold;line-height: 100%;margin-top: 0;margin-right: 0;margin-bottom: 10px;margin-left: 0;text-align: left"><?php echo $title ?></h4>
5 changes: 5 additions & 0 deletions application/views/email/spark_rejected.php
@@ -0,0 +1,5 @@
<?php $this->load->view('email/global/_header', array('teaser' => $teaser, 'title' => $title)) ?>

<?php echo $body ?>

<?php $this->load->view('email/global/_footer', array()) ?>
16 changes: 16 additions & 0 deletions certs/cert-5BCYACB2LWU32QMPCR7A5RSRMA7OIYS7.pem
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICdjCCAd+gAwIBAgIFZ89N7LQwDQYJKoZIhvcNAQEFBQAwUzELMAkGA1UEBhMC
VVMxEzARBgNVBAoTCkFtYXpvbi5jb20xDDAKBgNVBAsTA0FXUzEhMB8GA1UEAxMY
QVdTIExpbWl0ZWQtQXNzdXJhbmNlIENBMB4XDTExMTIzMTE1MzI1MFoXDTEyMTIz
MDE1MzI1MFowUjELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkFtYXpvbi5jb20xFzAV
BgNVBAsTDkFXUy1EZXZlbG9wZXJzMRUwEwYDVQQDEww3eTF1eGt5dWNhYzUwgZ8w
DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM3gSj4cZeCyMJgVM9E5bosVMxOfF8N9
mYwmWR6+v4aA4FoWGimY7Yfu+zLxL0T40JKjJzfWrr/Ekt5fs6T/xI9TI71mQwo0
O0WFKhsQO1dgHPiZHxt1IoY5jmUFrjDM2DzU352l+mjmd2ZMsq6huXtcHSAXeJvz
77Ets4gF8QTXAgMBAAGjVzBVMA4GA1UdDwEB/wQEAwIFoDAWBgNVHSUBAf8EDDAK
BggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRNspaK2hyWOYJ7F8U6
y+6wCZ2fTDANBgkqhkiG9w0BAQUFAAOBgQBPxVOQllyx2CL636Ap6klvSc5dPvpk
uZwuj08wuuSRHbIgwfvJmKzPRbDAO9DKd19vsjR+pfmzq8r/6LywCetSKHy6mHRU
Z2an5Cmdekjh26vAbJctFtjITDoJG28MI4uCHBi8fkuYgX/sjEAXBG2+ZKP54cQu
iKL2CJkNBWgGog==
-----END CERTIFICATE-----
Empty file added certs/index.html
Empty file.
1 change: 1 addition & 0 deletions sparks/amazon-ses/0.3.0/.gitignore
@@ -0,0 +1 @@
config/amazon_ses_real.php
8 changes: 8 additions & 0 deletions sparks/amazon-ses/0.3.0/CHANGELOG.md
@@ -0,0 +1,8 @@
Changelog
=========
This log includes all changes to the public API of this library. Check the project's commit history for a more detailed look and for changes that impact the internals of this library.

v0.3
----
* Added support for a vanity 'from' name. This can be set using the second parameter in the 'from' method or setting the 'amazon_ses_from_name' config parameter.
* Added an extra check to overcome conflicting certificates. Thanks Stephen Frank.
19 changes: 19 additions & 0 deletions sparks/amazon-ses/0.3.0/LICENSE.md
@@ -0,0 +1,19 @@
Copyright (c) 2011 Joël Cox and contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
97 changes: 97 additions & 0 deletions sparks/amazon-ses/0.3.0/README.md
@@ -0,0 +1,97 @@
CodeIgniter Amazon SES
======================
A CodeIgniter library to interact with Amazon Web Services (AWS) Simple Email Service (SES). This library was designed with the standard CodeIgniter email class in mind. As a result, most methods look the same, ensuring a minimal learning curve.

NOTE: this code is still under heavy development and currently provides only the very basics of the AWS SES API (don't you like acronyms?), sending email.

Requirements
------------
1. PHP 5.1+
2. [CodeIgniter 2.0+](http://codeigniter.com)
3. libcurl with OpenSSL support
4. Phil Sturgeon's CodeIgniter [cURL library](http://github.com/philsturgeon/codeigniter-curl)
5. A bundle of public root certificates (e.g. http://curl.haxx.se/ca/cacert.pem)
6. An [Amazon Web Services account](http://aws.amazon.com)

Spark
-------------
This library is also released as a [Spark](http://getsparks.org). If you use this library in any other way, **don't copy the autoload.php to your config directory**.

Documentation
-------------

### Configuration
This library expects a configuration file to function correctly. A template for this file is provided with the library.

### Verify email address
Before you can send your first message, Amazon SES requires that you verify your email address. This is to confirm that you own the email address, and to prevent others from using it.

Request to verify your email address as a sender.

$this->amazon_ses->verify_address('from@example.com');

Check whether a email address is verified as a sender.

$this->amazon_ses->address_is_verified('from@example.com');

### Recipients

Set the "To" address(es) for a message.

$this->amazon_ses->to('to1@example.com');

Set the "CC" address(es) (carbon copy) for a message.

$this->amazon_ses->cc('cc1@example.com, cc2@example.com');

Set the "BCC" address(es) (blind carbon copy) for a message.

$this->amazon_ses->bcc(array('bcc1@example.com', 'bcc2@example.com', 'bcc3@example.com'));

These three methods expect valid e-mail addresses as a string, array or comma separated list.

###Message

Set the sender address. You can also set this in your config file. The second parameter - the vanity name of the sender - is optional.

$this->amazon_ses->from('do_reply@example.com', 'Email monkey');

Set the subject for a message.

$this->amazon_ses->subject('Open me!');

Set the message to be sent.

$this->amazon_ses->message('<strong>Use HTML</strong>');

Set the alternative message (plain-text) to be sent. When not specified, an alternative message is generated by using PHP's strip_tags() function.

$this->amazon_ses->message_alt('No HTML?!');

Sends the message. Returns true on success.

$this->amazon_ses->send();

NOTE: All methods above are chainable, which means you can do the following

$this->amazon_ses->to('email@example.com')->subject('Yo!')->message('Sup dawg')->send();

###Misc

Sends the message in debug mode. In debug mode, the send() methods returns the actual API response instead of a boolean. Call this method before calling the send method.

$this->amazon_ses->debug(TRUE);

Preserves recipient after the message has been successfully send. When you call this method, all recipients will be preserved during the objects life. This makes it possible to sent an additional message without re-specifying the recipients.

$this->amazon_ses->destroy();

Contributing
------------
I am a firm believer of social coding, so <strike>if</strike> when you find a bug, please fork my code on [GitHub](http://github.com/joelcox/codeigniter-amazon-ses) and squash it. I will be happy to merge it back in to the code base (and add you to the "Thanks to" section). If you're not too comfortable using Git or messing with the inner workings of this library, please [open a new issue](http://github.com/joelcox/codeigniter-amazon-ses/issues).

Thanks to
---------
* [Phil Sturgeon](http://philsturgeon.co.uk), for creating the CodeIgniter [cURL library](http://github.com/philsturgeon/codeigniter-curl) and thus taking care of all the cURL hassle.
* [Ben Hartard](http://github.com/bhartard), for adding the email verification method.
* [Stephen Frank](https://github.com/stephenfrank), for sorting out SSL conflict issues.
21 changes: 21 additions & 0 deletions sparks/amazon-ses/0.3.0/config/amazon_ses.php
@@ -0,0 +1,21 @@
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Config for the Amazon Simple Email Service library
*
* @see ../libraries/Amazon_ses.php
*/
// Amazon credentials
$config['amazon_ses_secret_key'] = config_item('ses_secret_key');
$config['amazon_ses_access_key'] = config_item('ses_access_key');

// Adresses
$config['amazon_ses_from'] = 'ohcrap@getsparks.org';
$config['amazon_ses_from_name'] = 'GetSparks.org Team';
$config['amazon_ses_reply_to'] = 'ohcrap@getsparks.org';

// Path to certificate to verify SSL connection (i.e. 'certs/cacert.pem')
$config['amazon_ses_cert_path'] = 'certs/cert-5BCYACB2LWU32QMPCR7A5RSRMA7OIYS7.pem';

// Charset to be used, for example UTF-8, ISO-8859-1 or Shift_JIS. The SMTP
// protocol uses 7-bit ASCII by default
$config['amazon_ses_charset'] = 'UTF-8';
10 changes: 10 additions & 0 deletions sparks/amazon-ses/0.3.0/config/autoload.php
@@ -0,0 +1,10 @@
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
* Autoload for the Amazon Simple Email Service library. Only need when installing through GetSparks.org.
*
* @see ../libraries/Amazon_ses.php
*/

// Add autoload for Sparks
$autoload['libraries'] = array('amazon_ses');

0 comments on commit 22d6e26

Please sign in to comment.