litmus-instant 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +18 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +182 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +7 -0
  12. data/examples/Gemfile +4 -0
  13. data/examples/Gemfile.lock +32 -0
  14. data/examples/README.md +29 -0
  15. data/examples/email/test-email.html +330 -0
  16. data/examples/example_batch.rb +50 -0
  17. data/examples/example_simple.rb +35 -0
  18. data/fixtures/vcr_cassettes/Litmus_Instant/client_configurations/returns_a_Hash_of_clients_and_their_available_options.yml +419 -0
  19. data/fixtures/vcr_cassettes/Litmus_Instant/clients/returns_an_array_of_client_names.yml +86 -0
  20. data/fixtures/vcr_cassettes/Litmus_Instant/create_email/authenticated_with_invalid_email_Hash_raise_a_request_error.yml +77 -0
  21. data/fixtures/vcr_cassettes/Litmus_Instant/create_email/authenticated_with_valid_email_Hash_optional_end_user_id_is_relayed.yml +44 -0
  22. data/fixtures/vcr_cassettes/Litmus_Instant/create_email/authenticated_with_valid_email_Hash_prerequest_configurations_is_relayed.yml +55 -0
  23. data/fixtures/vcr_cassettes/Litmus_Instant/create_email/authenticated_with_valid_email_Hash_response_.yml +81 -0
  24. data/fixtures/vcr_cassettes/Litmus_Instant/create_email/unauthenticated_raises_an_authentication_error.yml +41 -0
  25. data/fixtures/vcr_cassettes/Litmus_Instant/get_preview/raises_NotFound_for_an_expired_email_guid.yml +1668 -0
  26. data/fixtures/vcr_cassettes/Litmus_Instant/get_preview/raises_RequestError_for_an_invalid_client.yml +79 -0
  27. data/fixtures/vcr_cassettes/Litmus_Instant/get_preview/raises_RequestError_for_an_invalid_email_guid.yml +39 -0
  28. data/fixtures/vcr_cassettes/Litmus_Instant/get_preview/returns_a_Hash_of_the_image_types.yml +85 -0
  29. data/fixtures/vcr_cassettes/Litmus_Instant/get_preview/supports_optional_capture_configuration.yml +121 -0
  30. data/fixtures/vcr_cassettes/Litmus_Instant/prefetch_previews/raises_RequestError_for_an_invalid_email_guid.yml +39 -0
  31. data/fixtures/vcr_cassettes/Litmus_Instant/prefetch_previews/raises_RequestError_if_any_invalid_configurations_are_present.yml +79 -0
  32. data/fixtures/vcr_cassettes/Litmus_Instant/prefetch_previews/responds_with_an_array_of_the_requested_configurations.yml +88 -0
  33. data/lib/litmus/instant.rb +216 -0
  34. data/lib/litmus/instant/version.rb +5 -0
  35. data/litmus-instant.gemspec +39 -0
  36. metadata +194 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b33b2790b147305678f1f7e5a78464370bfe0e30
4
+ data.tar.gz: cff4d00209f901e4bb1206de3a8c4bef0eaae521
5
+ SHA512:
6
+ metadata.gz: c3793e2e0cc82c28606803293972475c6c4c7cf9c6952072a4484afae498f1bf24ecb52085e737e38f88d2b5b550bb44ba8bc2aa22cd05ef92b29582a7cf959b
7
+ data.tar.gz: c3daaecb703ed155b23d67d5b76513e0f0a6680c2be05a0393378b2cbe2cd098689ed35da32f1073bfd991891e4bbfd2968715b794cdac703180ec40d0a2d3cd
@@ -0,0 +1,33 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ .rvmrc
29
+
30
+ /Gemfile.lock
31
+ .ruby-version
32
+ .ruby-gemset
33
+ .env
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in instant-api-ruby.gemspec
4
+ gemspec
@@ -0,0 +1,18 @@
1
+ ## Uncomment and set this to only include directories you want to watch
2
+ # directories %w(app lib config test spec features) \
3
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
4
+
5
+ guard :rspec, cmd: "source .env && bundle exec rspec" do
6
+ require "guard/rspec/dsl"
7
+ dsl = Guard::RSpec::Dsl.new(self)
8
+
9
+ # RSpec files
10
+ rspec = dsl.rspec
11
+ watch(rspec.spec_helper) { rspec.spec_dir }
12
+ watch(rspec.spec_support) { rspec.spec_dir }
13
+ watch(rspec.spec_files)
14
+
15
+ # Ruby files
16
+ ruby = dsl.ruby
17
+ dsl.watch_spec_files_for(ruby.lib_files)
18
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Rahim Packir Saibo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,182 @@
1
+ # Litmus Instant API Ruby
2
+
3
+ A ruby API client library for interacting with [Litmus Instant API](https://litmus.com/partners/api/documentation/instant/01-getting-started/) - the fastest way to include email previews from real clients in your application.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "litmus-instant"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install litmus-instant
20
+
21
+ ## Usage
22
+
23
+ Require the library and set your Instant API key
24
+
25
+ ```ruby
26
+ require "litmus/instant"
27
+ Litmus::Instant.api_key = "<YOUR INSTANT API KEY>"
28
+ ```
29
+
30
+ Prepare an email for capture
31
+
32
+ ```ruby
33
+ email_guid = Litmus::Instant.create_email(
34
+ plain_text: "Aloha World!"
35
+ )["email_guid"]
36
+ # => "755d1f9f-ad28-460f-8e45-632e0eceab32"
37
+ ```
38
+
39
+ Construct a preview URL for embedding client side or for downloading
40
+
41
+ ```ruby
42
+ @preview_url = Litmus::Instant.preview_image_url(email_guid, "OL2010")
43
+ # => "https://OL2010.instant-api.litmus.com/v1/emails/755d1f9f-ad28-460f-8e45-632e0eceab32/previews/OL2010/full"
44
+ ```
45
+
46
+ This could be used in a Rails erb template like so
47
+
48
+ ```html
49
+ <%= image_tag @preview_url %>
50
+ ```
51
+
52
+ ### Performance
53
+
54
+ In the example above the capture wouldn't be initiated until the end user's browser made the HTTP GET request to the preview URL. This would mean waiting the full capture time (a number of seconds) before the image data began to transfer.
55
+
56
+ Valuable time can be shaved here by pre-requesting required capture configurations as early as it's known they're needed. By the time the browser comes to request the preview the capture will be in progress or completed, so transfer of the image data will begin sooner. This also avoids browser connection limits delaying the initiation of capture for previews queued behind other requests.
57
+
58
+ This pre-request can be provided during email creation
59
+
60
+ ```ruby
61
+ Litmus::Instant.create_email(
62
+ plain_text: "Aloha World!",
63
+ configurations: [
64
+ { client: "OL2010" },
65
+ { client: "OL2013", images: "blocked" }
66
+ ]
67
+ )
68
+ # => {"email_guid"=>"99e313eb-5256-4824-b26f-2f9e031fa8b5",
69
+ # "configurations"=>
70
+ # [{"orientation"=>"vertical", "images"=>"allowed", "client"=>"OL2010"},
71
+ # {"orientation"=>"vertical", "images"=>"blocked", "client"=>"OL2013"}]}
72
+ ```
73
+
74
+ or via the dedicated method
75
+
76
+ ```ruby
77
+ Litmus::Instant.prefetch_previews(
78
+ email_guid, [
79
+ { client: "OL2010" },
80
+ { client: "OL2013", images: "blocked" }
81
+ ]
82
+ )
83
+ # => {"configurations"=>
84
+ # [{"orientation"=>"vertical", "images"=>"allowed", "client"=>"OL2010"},
85
+ # {"orientation"=>"vertical", "images"=>"blocked", "client"=>"OL2013"}]}
86
+ ```
87
+
88
+ For further information see the [performance section](https://litmus.com/partners/api/documentation/instant/04-performance/) of the Instant API documentation.
89
+
90
+ ### Handling errors
91
+
92
+ Various errors may occur can occur during normal usage of the API, please code defensively to handle these.
93
+
94
+ ```ruby
95
+ begin
96
+ # make Litmus::Instant api call
97
+ rescue Litmus::Instant::AuthenticationError => e
98
+ # eg an invalid API key, or API key not set
99
+ rescue Litmus::Instant::RequestError => e
100
+ # eg an invalid client configuration was requested
101
+ rescue Litmus::Instant::NotFound => e
102
+ # The most likely cause of this is an invalid email_guid, or expired email
103
+ rescue Litmus::Instant::TimeoutError => e
104
+ # An email client may timeout for various reasons, including upstream service
105
+ # issues for webmail clients, or unexpected behaviour with problematic email
106
+ # source
107
+ rescue Litmus::Instant::ServiceError => e
108
+ # eg a capacity issue or unexpected infrastracture issue
109
+ # This should occur extremely rarely
110
+ rescue Litmus::Instant::ApiError => e
111
+ # Catch all the above and any other API failure responses
112
+ rescue Litmus::Instant::NetworkError => e
113
+ # Convenience wrapper around general ruby networking errors
114
+ rescue Litmus::Instant::Error => e
115
+ # Base error class, parent of everything above
116
+ end
117
+ ```
118
+
119
+ Note that the default behaviour of the the embedable URL returned from `Litmus::Instant.preview_image_url` is to redirect to a fallback image if an error occurs during capture. This behavior can be overriden to raise errors by setting the `fallback` option to `false`.
120
+
121
+ ### Downloading previews server-side
122
+
123
+ The gem itself doesn't provide a dedicated method for downloading raw image data, only generating the URLs to download from. This was a conscious decision to leave the choice of tooling used for downloading the binary data open to the developer.
124
+
125
+ In the simplest case, downloading a single preview to a tempfile can be achieved with Ruby's [OpenURI](http://ruby-doc.org/stdlib-2.1.0/libdoc/open-uri/rdoc/OpenURI.html)
126
+
127
+ ```ruby
128
+ require "open-uri"
129
+ open @preview_url
130
+ # ...blocks for a few seconds...
131
+ # => #<File:/var/folders/st/813n6d9d0ts_hj8ktmx0p0hh0000gn/T/open-uri20151007-51192-k3a53m>
132
+ ```
133
+
134
+ A common use case is downloading a batch of previews for a selection of email clients. Often doing this as fast as possible is important for the desired experience in a waiting client application.
135
+
136
+ In this situation we recommend:
137
+
138
+ - pre-requesting known clients before download
139
+ - making parallel HTTP requests, with concurrency tuned to minimise wait time, maximise bandwidth usage, but minimise network contention issues.
140
+
141
+ When constrained by bandwidth, simply pre-requesting and then sequentially downloading one preview after another may yield the fastest completion time. In most situations, exceeding 15 concurrent connections is unlikely to improve overall completion time.
142
+
143
+ For managing parallel downloads in ruby, you could use multiple threads and Net:HTTP, em-http-request, or shell out to `wget` or `aria2`, however our example below uses [Typhoeus](https://github.com/typhoeus/typhoeus) which wraps libcurl.
144
+
145
+ ```ruby
146
+ require "typhoeus"
147
+
148
+ # prerequest capture on all clients in their default configuration
149
+ clients = Litmus::Instant.clients
150
+ configurations = clients.map { |client| { client: client } }
151
+ Litmus::Instant.prefetch_previews(email_guid, configurations)
152
+
153
+ hydra = Typhoeus::Hydra.new(max_concurrency: 15)
154
+ clients.each do |client|
155
+ preview_url = Litmus::Instant.preview_image_url(email_guid, client, capture_size: "thumb")
156
+ request = Typhoeus::Request.new(preview_url, followlocation: true)
157
+ request.on_complete do |response|
158
+ File.write("/tmp/#{email_guid}-#{client}.png", response.body)
159
+ end
160
+ hydra.queue(request)
161
+ end
162
+ hydra.run
163
+
164
+ ```
165
+
166
+ ## Development
167
+
168
+ After checking out the repo, run `bin/setup` to install dependencies. Then, with the `API_KEY` environment variable set appropriately, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
169
+
170
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
171
+
172
+ ## Contributing
173
+
174
+ Bug reports and pull requests are welcome on GitHub at https://github.com/litmus/instant-api-ruby.
175
+
176
+
177
+ ## License
178
+
179
+ © 2015 Litmus Software
180
+
181
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
182
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "litmus/instant"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "sinatra"
4
+ gem "litmus-instant", path: "../"
@@ -0,0 +1,32 @@
1
+ PATH
2
+ remote: ../../instant-api-ruby
3
+ specs:
4
+ litmus-instant (0.1.0)
5
+ httparty (~> 0.13.5)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ httparty (0.13.7)
11
+ json (~> 1.8)
12
+ multi_xml (>= 0.5.2)
13
+ json (1.8.3)
14
+ multi_xml (0.5.5)
15
+ rack (1.6.1)
16
+ rack-protection (1.5.3)
17
+ rack
18
+ sinatra (1.4.6)
19
+ rack (~> 1.4)
20
+ rack-protection (~> 1.4)
21
+ tilt (>= 1.3, < 3)
22
+ tilt (2.0.1)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ litmus-instant!
29
+ sinatra
30
+
31
+ BUNDLED WITH
32
+ 1.10.6
@@ -0,0 +1,29 @@
1
+ # Examples of InstantAPI usage
2
+
3
+ ## Prerequisites
4
+
5
+ - ruby
6
+ - bundler
7
+
8
+ ## Launch
9
+
10
+ ```
11
+ $ bundle
12
+ ```
13
+
14
+ and then
15
+
16
+ ```
17
+ $ API_KEY=replace_with_your_api_key ruby example_simple.rb
18
+ ```
19
+
20
+ or
21
+
22
+ ```
23
+ $ API_KEY=replace_with_your_api_key ruby example_batch.rb
24
+ ```
25
+
26
+
27
+ ## Open
28
+
29
+ Navigate to http://0.0.0.0:4567/example (or the port shown at launch)
@@ -0,0 +1,330 @@
1
+ <html>
2
+
3
+ <head>
4
+ <title>Litmus: The secret weapon for email marketers.</title>
5
+ <style type="text/css">
6
+ .ReadMsgBody {
7
+ width: 100%;
8
+ }
9
+ .ExternalClass {
10
+ width: 100%;
11
+ }
12
+
13
+ .appleBody a {color:#ffffff; text-decoration: none;}
14
+ .appleFooter a {color:#999999; text-decoration: none;}
15
+ blockquote .original-only, .WordSection1 .original-only {display: none !important;}
16
+ blockquote table.forwarded-only, .WordSection1 table.forwarded-only {display: block !important;}
17
+ </style>
18
+ </head>
19
+
20
+ <body style="margin: 0; padding: 0">
21
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
22
+ <tr>
23
+ <td bgcolor="#333333">
24
+ <div align="center" style="padding: 0px 15px 0px 15px;">
25
+ <table border="0" cellpadding="0" cellspacing="0" width="500">
26
+ <tr>
27
+ <td style="padding: 20px 0px 30px 0px;">
28
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
29
+ <tr>
30
+ <td width="138" align="left">
31
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/">
32
+ <img alt="Litmus" src="https://i9.createsend1.com/ei/y/AF/367/F50/033907/logodark.gif"
33
+ width="138" height="59" style="display: block; font-family: Georgia; font-style: italic; color: #e4b23b; font-size: 19px;"
34
+ border="0">
35
+ </a>
36
+ </td>
37
+ <td width="112">
38
+ <img alt="" src="https://i10.createsend1.com/ei/y/AF/367/F50/033907/spacer.gif"
39
+ width="112" height="1" border="0" style="display: none;">
40
+ </td>
41
+ <td width="250" align="right">
42
+ <table border="0" cellpadding="0" cellspacing="0">
43
+ <tr>
44
+ <td align="right" style="padding: 0 0 5px 0; font-size: 14px; font-family: Arial, sans-serif; color: #555555; text-decoration: none;">
45
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="color: #666666; text-decoration: none;">Mythbusting infographics, mobile opens at 43% + 25 inspirational emails!</a>
46
+ </td>
47
+ </tr>
48
+ <tr>
49
+ <td align="right">
50
+ <table border="0" cellpadding="0" cellspacing="0">
51
+ <tr>
52
+ <td align="right" style="padding: 0 3px 0 0;">
53
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-xx-xxxxxxx-xxxxxxxx-x/">
54
+ <img src="https://i1.createsend1.com/ei/y/AF/367/F50/033907/icon-twitter.gif"
55
+ alt="" border="0" width="25" height="14" style="display: block">
56
+ </a>
57
+ </td>
58
+ <td style="padding: 0 15px 0 0;" align="left">
59
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-xx-xxxxxxx-xxxxxxxx-x/" style="font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 24px; color: #555555; text-decoration: none;">Tweet this</a>
60
+ </td>
61
+ <td align="right" style="padding: 0 3px 0 0;">
62
+ <a href="http://xxxxxx.xxxxxxxxxxxxxxxxx.xxx/x-xxxxxxxx-X0000X00-xxxxxxx-x-x">
63
+ <img src="https://i4.createsend1.com/ei/y/AF/367/F50/033907/icon-email.gif" alt=""
64
+ border="0" width="21" height="14" style="display: block">
65
+ </a>
66
+ </td>
67
+ <td align="left">
68
+ <a href="http://xxxxxx.xxxxxxxxxxxxxxxxx.xxx/x-xxxxxxxx-X0000X00-xxxxxxx-x-x"
69
+ style="font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 24px; color: #555555; text-decoration: none;">Forward this</a>
70
+ </td>
71
+ </tr>
72
+ </table>
73
+ </td>
74
+ </tr>
75
+ </table>
76
+ </td>
77
+ </tr>
78
+ </table>
79
+ </td>
80
+ </tr>
81
+ </table>
82
+ </div>
83
+ </td>
84
+ </tr>
85
+ </table>
86
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
87
+ <tr>
88
+ <td bgcolor="#1A6D73" align="center" style="padding: 25px 15px 0 15px;">
89
+ <table border="0" cellpadding="0" cellspacing="0" width="500">
90
+ <tr>
91
+ <td>
92
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
93
+ <tr>
94
+ <td colspan="2" align="left" style="font-size: 34px; letter-spacing: -1px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #FFFFFF; text-shadow: 1px 1px 1px #1C2D2D;">Crafting your perfect subject line</td>
95
+ </tr>
96
+ <tr>
97
+ <td align="left" valign="top">
98
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
99
+ <tr>
100
+ <td style="padding: 20px 10px 0 0; font-size: 19px; line-height: 27px; font-family: Helvetica, Arial, sans-serif; color: #031415;">We bust myths, cover risky practices and report on what works (most of the time).
101
+ Get your email opened and read.</td>
102
+ </tr>
103
+ <tr>
104
+ <td style="padding: 25px 0 0 0;">
105
+ <table border="0" cellspacing="0" cellpadding="0">
106
+ <tr>
107
+ <td bgcolor="#499982" style="padding: 8px 10px 7px 10px; -webkit-border-radius:3px; border-radius:3px">
108
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="font-size: 22px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #1C2D2D; text-decoration: none;">View infographic &rarr;</a>
109
+ </td>
110
+ </tr>
111
+ </table>
112
+ </td>
113
+ </tr>
114
+ </table>
115
+ </td>
116
+ <td width="260" valign="top">
117
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/">
118
+ <img src="https://i2.createsend1.com/ei/y/AF/367/F50/033907/finding-the-perfect-subject.gif"
119
+ alt="" height="260" width="260" border="0" style="display: block; font-family: Arial; color: #13263F;">
120
+ </a>
121
+ </td>
122
+ </tr>
123
+ </table>
124
+ </td>
125
+ </tr>
126
+ </table>
127
+ </td>
128
+ </tr>
129
+ </table>
130
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
131
+ <tr>
132
+ <td bgcolor="#499982" style="padding: 5px 15px 0px 15px;">
133
+ <div align="center">
134
+ <table border="0" cellpadding="0" cellspacing="0" width="500">
135
+ <tr>
136
+ <td>
137
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/">
138
+ <img src="https://i3.createsend1.com/ei/y/AF/367/F50/033907/mobile-opens.gif"
139
+ alt="" width="200" height="300" border="0" style="display: block;">
140
+ </a>
141
+ </td>
142
+ <td>
143
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
144
+ <tr>
145
+ <td align="left" style="padding: 0 0 5px 25px; font-size: 24px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #363838; letter-spacing: -1px;">Mobile opens peak at 43% in December</td>
146
+ </tr>
147
+ <tr>
148
+ <td align="left" style="padding: 10px 0 15px 25px; font-size: 16px; line-height: 20px; font-family: Helvetica, Arial, sans-serif; color: #222222; ">iPhone still reigns supreme and Android advances to #6. Find out what else happened
149
+ in our 1-minute video.</td>
150
+ </tr>
151
+ <tr>
152
+ <td style="padding: 0 0 0 25px;">
153
+ <table border="0" cellspacing="0" cellpadding="0">
154
+ <tr>
155
+ <td bgcolor="#1C2D2D" style="padding: 7px 10px 6px 8px; -webkit-border-radius:3px; border-radius:3px">
156
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="font-size: 20px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #6a9177; text-decoration: none;">Watch now &rarr;</a>
157
+ </td>
158
+ </tr>
159
+ </table>
160
+ </td>
161
+ </tr>
162
+ </table>
163
+ </td>
164
+ </tr>
165
+ </table>
166
+ </div>
167
+ </td>
168
+ </tr>
169
+ </table>
170
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
171
+ <tr>
172
+ <td bgcolor="#D9B282" align="center" style="padding: 15px 15px 5px 15px;">
173
+ <table border="0" cellpadding="0" cellspacing="0" width="500">
174
+ <tr>
175
+ <td>
176
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
177
+ <tr>
178
+ <td align="left" width="279" valign="middle">
179
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
180
+ <tr>
181
+ <td align="left" style="font-size: 23px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #625144;">25 days of inspirational email designs</td>
182
+ </tr>
183
+ <tr>
184
+ <td align="left" style="padding: 10px 0 0 0; font-size: 16px; line-height: 22px; font-family: Helvetica, Arial, sans-serif; color: #816149;"><b>Looking for email inspiration?</b>
185
+
186
+ </tr>
187
+ <tr>
188
+ <td align="left" style="padding: 5px 0 15px 0; font-size: 16px; line-height: 22px; font-family: Helvetica, Arial, sans-serif; color: #816149;">Our &ldquo;25 days of inspiration&rdquo; gathered great examples of responsive
189
+ designs, transactional messages, welcome emails &amp; more!</td>
190
+ </tr>
191
+ <tr>
192
+ <td>
193
+ <table border="0" cellspacing="0" cellpadding="0">
194
+ <tr>
195
+ <td bgcolor="#625144" style="padding: 6px 9px 5px 7px;-webkit-border-radius:3px; border-radius:3px">
196
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="font-size: 18px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #D9B282; text-decoration: none;">Get inspired &rarr;</a>
197
+ </td>
198
+ </tr>
199
+ </table>
200
+ </td>
201
+ </tr>
202
+ </table>
203
+ </td>
204
+ <td width="221" valign="top">
205
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/">
206
+ <img src="https://i5.createsend1.com/ei/y/AF/367/F50/033907/inspiration.gif" alt=""
207
+ height="300" width="221" border="0" style="display: block; font-family: Arial; color: #13263F;">
208
+ </a>
209
+ </td>
210
+ </tr>
211
+ </table>
212
+ </td>
213
+ </tr>
214
+ </table>
215
+ </td>
216
+ </tr>
217
+ </table>
218
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
219
+ <tr>
220
+ <td bgcolor="#F2845C" style="padding: 35px 15px 25px 15px;">
221
+ <div align="center">
222
+ <table border="0" cellpadding="0" cellspacing="0" width="500">
223
+ <tr>
224
+ <td valign="top">
225
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/">
226
+ <img src="https://i6.createsend1.com/ei/y/AF/367/F50/033907/landing-page-testing.gif"
227
+ alt="" width="200" height="250" border="0" style="display: block;">
228
+ </a>
229
+ </td>
230
+ <td valign="top">
231
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
232
+ <tr>
233
+ <td align="left" style="padding: 13px 0 10px 25px;">
234
+ <table border="0" cellspacing="0" cellpadding="0">
235
+ <tr>
236
+ <td bgcolor="#b36447" style="padding: 5px 7px 4px 7px;-webkit-border-radius:10px; border-radius:10px">
237
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="font-size: 13px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #f2845c; text-decoration: none;">New Feature</a>
238
+ </td>
239
+ </tr>
240
+ </table>
241
+ </td>
242
+ </tr>
243
+ <tr>
244
+ <td align="left" style="padding: 0 0 5px 25px; font-size: 23px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #333333; letter-spacing: -1px;">Never click links when testing email again!</td>
245
+ </tr>
246
+ <tr>
247
+ <td align="left" style="padding: 5px 0 10px 25px; font-size: 16px; line-height: 20px; font-family: Helvetica, Arial, sans-serif; color: #222222; text-decoration: none;">Automatically validate all the links in your email with landing page testing.
248
+ Available now in all Litmus accounts.</td>
249
+ </tr>
250
+ <tr>
251
+ <td style="padding: 5px 0 0 25px;">
252
+ <table border="0" cellspacing="0" cellpadding="0">
253
+ <tr>
254
+ <td bgcolor="#f6a88c" style="padding: 5px 8px 4px 6px; -webkit-border-radius:3px; border-radius:3px">
255
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="font-size: 18px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #a74a28; text-decoration: none;">Learn more &amp; free trial &rarr;</a>
256
+ </td>
257
+ </tr>
258
+ </table>
259
+ </td>
260
+ </tr>
261
+ </table>
262
+ </td>
263
+ </tr>
264
+ </table>
265
+ </div>
266
+ </td>
267
+ </tr>
268
+ </table>
269
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" class="forwarded-only"
270
+ style="display: none;">
271
+ <tr>
272
+ <td bgcolor="#161616" align="center">
273
+ <table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
274
+ <tr>
275
+ <td style="padding: 20px 0px 20px 0px;" align="center">
276
+ <table width="500" border="0" cellspacing="0" cellpadding="0" align="center">
277
+ <tr>
278
+ <td align="center" bgcolor="#000000" style="padding: 8px 8px 7px 8px; -webkit-border-radius:3px; border-radius:3px">
279
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="font-size: 14px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; color: #a74a28; text-decoration: none;">Subscribe To Our Newsletter</a>
280
+ </td>
281
+ </tr>
282
+ </table>
283
+ </td>
284
+ </tr>
285
+ </table>
286
+ </td>
287
+ </tr>
288
+ </table>
289
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
290
+ <tr>
291
+ <td bgcolor="#333333" align="center">
292
+ <table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
293
+ <tr>
294
+ <td style="padding: 20px 0px 20px 0px;">
295
+ <table width="500" border="0" cellspacing="0" cellpadding="0" align="center">
296
+ <tr>
297
+ <td width="138" valign="middle">
298
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/">
299
+ <img alt="Litmus" src="https://i9.createsend1.com/ei/y/AF/367/F50/033907/logodark.gif"
300
+ width="138" height="59" style="display: block; font-family: Arial; color: #ffffff; font-size: 14px;"
301
+ border="0">
302
+ </a>
303
+ </td>
304
+ <td width="20">
305
+ <img alt="" src="https://i10.createsend1.com/ei/y/AF/367/F50/033907/spacer.gif"
306
+ width="20" height="1" border="0" style="display: block;">
307
+ </td>
308
+ <td align="center" width="342" valign="middle" style="font-size: 12px; line-height: 18px; font-family: Helvetica, Arial, sans-serif; color:#999999; -webkit-text-size-adjust: none"><span class="appleFooter" style="color:#999999; -webkit-text-size-adjust: none">675 Massachusetts Ave., Cambridge, MA 02139, USA</span>
309
+
310
+ <br>
311
+ <a href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" class="original-only"
312
+ style="color: #999999; text-decoration: none; -webkit-text-size-adjust: none">Unsubscribe</a><span class="original-only" style="font-family: Arial, sans-serif; font-size: 12px; color: #555555; font-weight:bold; -webkit-text-size-adjust: none">&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;</span>
313
+ <a
314
+ href="http://xxxxxx.xxxxxxxxxx0.xxx/x/x-x-xxxxxxx-xxxxxxxx-x/" style="color: #999999; text-decoration: none; -webkit-text-size-adjust: none">View this email in your browser</a>
315
+ </td>
316
+ </tr>
317
+ </table>
318
+ </td>
319
+ </tr>
320
+ </table>
321
+ </td>
322
+ </tr>
323
+ </table>
324
+ <style type="text/css">
325
+ blockquote .original-only, .WordSection1 .original-only {display: none !important;}
326
+ blockquote table.forwarded-only, .WordSection1 table.forwarded-only {display: block !important;}
327
+ </style>
328
+ </body>
329
+
330
+ </html>