Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 837bfa612b7bc8f0a7669a9e35d23e243bfb2145 Jonathan Lloyd committed Nov 5, 2011
Showing with 237 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. 0 dist.ini
  3. +55 −0 example/send_email.pl
  4. +21 −0 lib/WebService/SendGrid.pm
  5. +67 −0 lib/WebService/SendGrid/Mail.pm
  6. +93 −0 t/04_send_email.t
1 .gitignore
@@ -0,0 +1 @@
+.DS_Store
0 dist.ini
No changes.
55 example/send_email.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings FATAL => 'all';
+
+use Data::Show;
+use JSON::XS;
+use Perl6::Slurp;
+
+my $list = '/Users/jlloyd/Backup/Constant Contact/Contacts.csv';
+my $html = slurp '/Users/jlloyd/Desktop/email/email.html';
+
+use SendGrid::Mail;
+use Data::Validate::Email qw(is_email is_email_rfc822);
+
+my @rows;
+use Text::CSV_XS;
+my $csv = Text::CSV_XS->new ({ binary => 1 }) or die "Cannot use CSV: ".Text::CSV_XS->error_diag ();
+open my $fh, "<:encoding(utf8)", $list or die "$list: $!";
+while (my $row = $csv->getline ($fh)) {
+ if (is_email($row->[0])) {
+ push @rows, $row->[0]
+ }
+ else {
+ print "Invalid email : " . $row->[0] . "\n";
+ }
+}
+$csv->eof or $csv->error_diag ();
+close $fh;
+
+my $data;
+$data->{category} = 'An Evening With Musicals - 09/25/11';
+$data->{filters}{subscriptiontrack}{settings}{enable} = 1;
+$data->{filters}{subscriptiontrack}{settings}{'text/html'} =
+ '<p>If you&#39;d like to unsubscribe and stop receiving these emails <% click here %>.</p>';
+
+my $count = 0;
+my $total = scalar @rows;
+for my $email (@rows) {
+
+ $count++;
+ print "($count/$total) Sending email to $email\n";
+
+ my $mail = SendGrid::Mail->new(
+ to => $email,
+ from => 'info@thetribeproductions.org',
+ 'x-smtpapi' => encode_json $data,
+ subject => 'Spend "An Evening With Musicals" to Benefit theTRIBE\'s 2012 Season!',
+ #text => 'This is a test message',
+ html => $html
+ );
+
+ $mail->send;
+
+}
21 lib/WebService/SendGrid.pm
@@ -0,0 +1,21 @@
+package WebService::SendGrid;
+use Moose;
+use MooseX::Method::Signatures;
+
+with 'WebService::Dispatcher::Curl';
+
+has 'api_user' => (
+ is => 'rw',
+ isa => 'Str',
+ required => 1,
+ default => 'webmaster@lifegames.org'
+);
+has 'api_key' => (
+ is => 'rw',
+ isa => 'Str',
+ required => 1,
+ default => 'b5l2v2v3970f16gJRL80'
+);
+has 'api_uri' => (is => 'ro', isa => 'Str', default => 'https://sendgrid.com/api/mail.send.json');
+
+1;
67 lib/WebService/SendGrid/Mail.pm
@@ -0,0 +1,67 @@
+package WebService::SendGrid::Mail;
+use Moose;
+use MooseX::Method::Signatures;
+
+extends 'SendGrid';
+
+use URI;
+use Carp;
+use JSON::XS;
+use Data::Show;
+use Util::Types qw(Email);
+use DateTime::Format::Mail;
+
+has 'to' => ( is => 'rw', isa => 'Email | ArrayRef[Email]', required => 1 );
+has 'toname' => ( is => 'rw', isa => 'Str | ArrayRef', required => 0 );
+has 'bcc' => ( is => 'rw', isa => 'Email | ArrayRef[Email]', required => 0 );
+has 'from' => ( is => 'rw', isa => 'Email', required => 1 );
+has 'fromname' => ( is => 'rw', isa => 'Str', required => 0 );
+has 'replyto' => ( is => 'rw', isa => 'Email', required => 0 );
+has 'x-smtpapi' => ( is => 'rw', isa => 'Str', required => 0 );
+has 'subject' => ( is => 'rw', isa => 'Str', required => 1 );
+has 'files' => ( is => 'rw', isa => 'HashRef', required => 0 );
+# files[file1.doc]=example.doc&files[file2.pdf]=example.pdf
+has 'headers' => ( is => 'rw', isa => 'HashRef', required => 0 );
+# A collection of key/value pairs in JSON format
+has 'date' => ( is => 'rw', isa => 'Str', required => 1, default => sub {
+ DateTime::Format::Mail->format_datetime( DateTime->now() );
+ # RFC 2822 formatted date
+});
+has 'text' => ( is => 'rw', isa => 'Str', required => 0 );
+has 'html' => ( is => 'rw', isa => 'Str', required => 0 );
+
+
+method send {
+ # must have text and/or HTML
+ croak "No content" unless ( $self->text || $self->html );
+
+ my %data;
+ for my $attr ( $self->meta->get_all_attributes ) {
+ next unless __PACKAGE__ eq $attr->definition_context->{package};
+ my $name = $attr->name;
+ $data{$name} = $self->$name if $self->$name;
+ }
+
+ $data{$_} = $self->$_ for qw(api_user api_key);
+
+ my $uri = URI->new('http:');
+ $uri->query_form(%data);
+
+ my $req = HTTP::Request->new;
+ $req->method('POST');
+ $req->uri($self->api_uri);
+ $req->content($uri->query);
+
+ # if the module is being called from a test file
+ # always send a successful response
+ my ($package, $filename, $line) = caller;
+ return { message => 'success' } if $filename =~ /\.t$/;
+
+ my $res = $self->http_request($req);
+ my $content = decode_json $res->content;
+ return $res->code == 200 ? $content : undef;
+
+
+}
+
+1;
93 t/04_send_email.t
@@ -0,0 +1,93 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings FATAL => 'all';
+
+use Data::Show;
+use Try::Tiny;
+use Test::More tests => 23;
+
+my %data = (
+ to => 'majrmovies@gmail.com',
+ from => 'webmaster@lifegames.org',
+ subject => 'This is a test',
+ text => 'This is a test message',
+ html => '<html><head></head><body>This is a test HTML message</body></html>'
+);
+
+BEGIN { use_ok( 'SendGrid::Mail' ); }
+require_ok( 'SendGrid::Mail' );
+
+my $mail = SendGrid::Mail->new(%data);
+isa_ok($mail, 'SendGrid::Mail');
+can_ok($mail, qw(send));
+
+my $res = $mail->send;
+is (ref $res, 'HASH', 'Valid return type');
+ok (defined $res->{message}, 'Valid return data');
+ok ($res->{message} eq 'success', 'Successful response');
+
+try {
+ my $mail = SendGrid::Mail->new;
+}
+catch {
+ my $regex = qr/Attribute \((to|from|subject|date)\) is required/;
+ like ($_, $regex, 'Requirements test');
+};
+
+for my $attr (qw(to from bcc replyto)) {
+ try {
+ my %data = %data;
+ $data{$attr} = 'Bad email';
+ my $mail = SendGrid::Mail->new(%data);
+ }
+ catch {
+ my $regex = qr/Attribute \($attr\) does not pass the type constraint/;
+ like ($_, $regex, 'Email format test');
+ };
+}
+
+my @array_of_email_arrays;
+push @array_of_email_arrays, ['good_email@example.com', 'fine_email@examples.com'];
+push @array_of_email_arrays, ['good_email@example.com', 'Bad email'];
+push @array_of_email_arrays, ['Bad email', 'good_email@example.com'];
+push @array_of_email_arrays, ['Bad email', 'Bad Email'];
+
+for my $attr (qw(to bcc)) {
+ for my $test (@array_of_email_arrays) {
+ try {
+ my %data = %data;
+ $data{$attr} = $test;
+ my $mail = SendGrid::Mail->new(%data);
+ }
+ catch {
+ my $regex = qr/Attribute \($attr\) does not pass the type constraint/;
+ like ($_, $regex, 'Multiple Email format test');
+ };
+ }
+}
+
+for my $attr (qw(html text)) {
+ try {
+ my %data = %data;
+ delete $data{$attr};
+ my $mail = SendGrid::Mail->new(%data);
+ }
+ catch {
+ fail('Either/or Content test');
+ }
+ finally {
+ pass('Either/or Content test');
+ };
+}
+
+try {
+ my %data = %data;
+ delete $data{$_} for qw(text html);
+ my $mail = SendGrid::Mail->new(%data);
+ $mail->send;
+}
+catch {
+ my $regex = qr/No content/;
+ like ($_, $regex, 'And Content Test');
+};

0 comments on commit 837bfa6

Please sign in to comment.