├── lib ├── simple_spark │ ├── version.rb │ ├── endpoints │ │ ├── message_events.rb │ │ ├── inbound_domains.rb │ │ ├── subaccounts.rb │ │ ├── suppression_list.rb │ │ ├── relay_webhooks.rb │ │ ├── transmissions.rb │ │ ├── webhooks.rb │ │ ├── sending_domains.rb │ │ ├── templates.rb │ │ └── metrics.rb │ ├── exceptions.rb │ └── client.rb └── simple_spark.rb ├── spec ├── spec_helper.rb └── simple_spark │ ├── exceptions_spec.rb │ └── client_spec.rb ├── Guardfile ├── .gitignore ├── Rakefile ├── .travis.yml ├── .rubocop.yml ├── Gemfile ├── simple_spark.gemspec ├── LICENSE.txt └── README.md /lib/simple_spark/version.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | VERSION = '1.0.4' 3 | end 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'simple_spark' 2 | require 'climate_control' 3 | 4 | def with_modified_env(options, &block) 5 | ClimateControl.modify(options, &block) 6 | end 7 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | guard :rspec, cmd: 'rspec' do 2 | # watch /lib/ files 3 | watch(%r{^lib/(.+).rb$}) do |m| 4 | "spec/#{m[1]}_spec.rb" 5 | end 6 | 7 | # watch /spec/ files 8 | watch(%r{^spec/(.+).rb$}) do |m| 9 | "spec/#{m[1]}.rb" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.bundle 19 | *.so 20 | *.o 21 | *.a 22 | mkmf.log 23 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rspec/core/rake_task' 2 | require 'bundler/gem_tasks' 3 | 4 | # Default directory to look in is `/specs` 5 | # Run with `rake spec` 6 | RSpec::Core::RakeTask.new(:spec) do |task| 7 | task.rspec_opts = ['--color', '--format', 'progress'] 8 | end 9 | 10 | task :default => :spec 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | cache: bundler 3 | 4 | rvm: 5 | - 2.2.2 6 | 7 | script: 'bundle exec rake' 8 | 9 | bundler_args: --without development debug 10 | 11 | notifications: 12 | email: 13 | recipients: 14 | - jakcharlton@gmail.com 15 | on_failure: change 16 | on_success: never 17 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | Metrics/LineLength: 2 | Max: 250 3 | 4 | Metrics/MethodLength: 5 | Max: 20 6 | 7 | Metrics/AbcSize: 8 | # The ABC size is a calculated magnitude, so this number can be a Fixnum or 9 | # a Float. 10 | Max: 25 11 | 12 | AllCops: 13 | Exclude: 14 | - 'db/**/*' 15 | - 'config/**/*' 16 | - 'tmp/**/*' 17 | - 'log/**/*' 18 | - 'bin/**/*' 19 | 20 | -------------------------------------------------------------------------------- /spec/simple_spark/exceptions_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SimpleSpark::Exceptions::Error do 4 | describe :fail_with_exception_for_status do 5 | it 'will respond with the SparkPost error code' do 6 | errors = [{'message' => "Test Error Message", 'code' => 3005}] 7 | expect{SimpleSpark::Exceptions::Error.fail_with_exception_for_status(400, errors)}.to raise_error(SimpleSpark::Exceptions::BadRequest, "Test Error Message 400 (Error Code: 3005)") 8 | end 9 | end 10 | end -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in sparkpost-snap.gemspec 4 | gemspec 5 | 6 | group :development, :test do 7 | gem 'bundler', '~> 1.6' 8 | gem 'rake', '~> 0.9.6' 9 | gem 'rspec', '~> 3.4.0' 10 | gem 'rspec-nc', '~> 0' 11 | gem 'climate_control', '~> 0' 12 | end 13 | 14 | group :development do 15 | gem 'guard', '~> 2.13' 16 | gem 'guard-rspec', '~> 4.6.4' 17 | gem 'pry', '~> 0' 18 | gem 'pry-remote', '~> 0' 19 | gem 'pry-nav', '~> 0' 20 | end 21 | -------------------------------------------------------------------------------- /lib/simple_spark.rb: -------------------------------------------------------------------------------- 1 | require 'simple_spark/version' 2 | require 'simple_spark/client' 3 | require 'simple_spark/exceptions' 4 | require 'simple_spark/endpoints/metrics' 5 | require 'simple_spark/endpoints/transmissions' 6 | require 'simple_spark/endpoints/templates' 7 | require 'simple_spark/endpoints/inbound_domains' 8 | require 'simple_spark/endpoints/sending_domains' 9 | require 'simple_spark/endpoints/message_events' 10 | require 'simple_spark/endpoints/webhooks' 11 | require 'simple_spark/endpoints/relay_webhooks' 12 | require 'simple_spark/endpoints/subaccounts' 13 | require 'simple_spark/endpoints/suppression_list' 14 | 15 | -------------------------------------------------------------------------------- /simple_spark.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'simple_spark/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'simple_spark' 8 | spec.version = SimpleSpark::VERSION 9 | spec.authors = ['Jak Charlton'] 10 | spec.email = ['jakcharlton@gmail.com'] 11 | spec.summary = 'A library for accessing the SparkPost REST API http://www.sparkpost.com' 12 | spec.description = 'An alternative to the official SparkPost Ruby gem' 13 | spec.homepage = '' 14 | spec.license = 'MIT' 15 | 16 | spec.files = `git ls-files -z`.split("\x0") 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ['lib'] 20 | 21 | 22 | spec.add_dependency 'json', '>= 1.7.7', '< 2.0' 23 | spec.add_dependency 'excon', '>= 0.16.0', '< 1.0' 24 | end 25 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Jak Charlton 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/message_events.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /message-events endpoint 4 | # @note See: https://developers.sparkpost.com/api/#/reference/message-events 5 | class MessageEvents 6 | attr_accessor :client 7 | 8 | def initialize(client) 9 | @client = client 10 | end 11 | 12 | # Returns sample message_events 13 | # @param events [String] Event types for which to get a sample payload, use the Webhooks Events endpoint to list the 14 | # available event types, defaults to all event types 15 | # @return [Array] a list of sample MessageEvent hash objects 16 | # @note See: https://developers.sparkpost.com/api/#/reference/message-events/events-samples 17 | def samples(events = nil) 18 | query_params = events.nil? ? {} : { events: events } 19 | @client.call(method: :get, path: 'message-events/events/samples', query_values: query_params) 20 | end 21 | 22 | # Perform a filtered search for message event data. The response is sorted by descending timestamp. 23 | # @param params [String] Params to use in the search 24 | # @return [Array] a list of MessageEvent hash objects 25 | # @note See: https://developers.sparkpost.com/api/#/reference/message-events/search-for-message-events 26 | def search(params = {}) 27 | @client.call(method: :get, path: 'message-events', query_values: params) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/simple_spark/exceptions.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Exceptions 3 | # Adding an object to the exception to pass errors back 4 | # begin 5 | # raise Error.new({ id: '1' }), "a message" 6 | # rescue Error => e 7 | # puts e.message # => "a message" 8 | # puts e.object # => { id: '1' } 9 | # end 10 | class Error < StandardError 11 | attr_reader :object 12 | 13 | def initialize(object = nil) 14 | @object = object 15 | end 16 | 17 | def self.fail_with_exception_for_status(status, errors) 18 | exception = status_codes[status.to_s] || status_codes['default'] 19 | fail exception.new(errors), errors.map { |e| "#{e['message']} #{status} (Error Code: #{e['code']})" + (e['description'] ? ": #{e['description']}" : '') }.join(', ') 20 | end 21 | 22 | def self.status_codes 23 | { 24 | 'default' => Exceptions::UnprocessableEntity, 25 | '400' => Exceptions::BadRequest, 26 | '404' => Exceptions::NotFound, 27 | '422' => Exceptions::UnprocessableEntity, 28 | '420' => Exceptions::ThrottleLimitExceeded, 29 | '429' => Exceptions::ThrottleLimitExceeded 30 | } 31 | end 32 | end 33 | 34 | class InvalidConfiguration < Error; end 35 | class BadRequest < Error; end 36 | class NotFound < Error; end 37 | class UnprocessableEntity < Error; end 38 | class ThrottleLimitExceeded < Error; end 39 | class GatewayTimeoutExceeded < Error; end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/inbound_domains.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /inbound-domains endpoint 4 | # See: https://developers.sparkpost.com/api/#/reference/inbound-domains 5 | class InboundDomains 6 | attr_accessor :client 7 | 8 | def initialize(client) 9 | @client = client 10 | end 11 | 12 | # Lists your inbound domains 13 | # @return [Array] a list of Inbound Domain hash objects 14 | # @note See: https://developers.sparkpost.com/api/#/reference/inbound-domains/create-and-list 15 | def list 16 | @client.call(method: :get, path: 'inbound-domains') 17 | end 18 | 19 | # Create an inbound domain 20 | # @param domain_name [String] the domain name to create 21 | # @note See: https://developers.sparkpost.com/api/#/reference/inbound-domains/create-and-list 22 | def create(domain_name) 23 | @client.call(method: :post, path: 'inbound-domains', body_values: { domain: domain_name }) 24 | end 25 | 26 | # Retrieve an inbound domain 27 | # @param domain_name [String] the domain name to retrieve 28 | # @return [Hash] an Inbound Domain hash object 29 | # @note See: https://developers.sparkpost.com/api/#/reference/inbound-domains/retrieve-and-delete 30 | def retrieve(domain_name) 31 | domain_name = @client.url_encode(domain_name) 32 | @client.call(method: :get, path: "inbound-domains/#{domain_name}") 33 | end 34 | 35 | # Delete an inbound domain 36 | # @param domain_name [String] the domain name to delete 37 | # @note See: https://developers.sparkpost.com/api/#/reference/inbound-domains/retrieve-and-delete 38 | def delete(domain_name) 39 | domain_name = @client.url_encode(domain_name) 40 | @client.call(method: :delete, path: "inbound-domains/#{domain_name}") 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/subaccounts.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /subaccounts endpoint 4 | # @note Example subaccount 5 | # @note See: https://developers.sparkpost.com/api/#/reference/subaccounts 6 | class Subaccounts 7 | attr_accessor :client 8 | 9 | def initialize(client) 10 | @client = client 11 | end 12 | 13 | # List subaccounts 14 | # @return [Array] a list of Subaccount hash objects 15 | # @note See: https://developers.sparkpost.com/api/#/reference/subaccounts/subaccounts-collection/list-subaccounts 16 | def list 17 | @client.call(method: :get, path: 'subaccounts') 18 | end 19 | 20 | # Create a subaccount 21 | # @param values [Hash] the values to create the subaccount with 22 | # @note Example: 23 | # values = { 24 | # "name": "Sparkle Ponies", 25 | # "key_label": "API Key for Sparkle Ponies Subaccount", 26 | # "key_grants": ["smtp/inject", "sending_domains/manage", "message_events/view", "suppression_lists/manage"] 27 | # } 28 | # @note See: https://developers.sparkpost.com/api/#/reference/subaccounts/subaccounts-collection/create-new-subaccount 29 | def create(values) 30 | @client.call(method: :post, path: 'subaccounts', body_values: values) 31 | end 32 | 33 | # Retrieve details about a subaccount by specifying its id 34 | # @param id [Integer] the ID of the subaccount 35 | # @return [Hash] an Subaccount hash object 36 | # @note See: https://developers.sparkpost.com/api/#/reference/subaccounts/subaccounts-entity/list-specific-subaccount 37 | def retrieve(id) 38 | @client.call(method: :get, path: "subaccounts/#{id}") 39 | end 40 | 41 | # Update a Subaccount by its ID 42 | # @param id [Integer] the ID of the subaccount 43 | # @param values [Hash] the values to update the subaccount with 44 | # @note See: https://developers.sparkpost.com/api/#/reference/subaccounts/subaccounts-entity/edit-a-subaccount 45 | def update(id, values) 46 | @client.call(method: :put, path: "subaccounts/#{id}", body_values: values) 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/suppression_list.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /suppression-list endpoint 4 | # @note Example suppression list recipient 5 | # { "recipient": "rcpt_1@example.com", "transactional": true, 6 | # "description": "User requested to not receive any transactional emails." } 7 | # @note See: https://developers.sparkpost.com/api/suppression-list 8 | class SuppressionList 9 | attr_accessor :client 10 | 11 | def initialize(client) 12 | @client = client 13 | end 14 | 15 | # Search for list entries 16 | # @param params [String] Params to use in the search 17 | # @return [Array] a list of sample Suppression Status hash objects 18 | # @note See: https://developers.sparkpost.com/api/suppression-list#suppression-list-search-get 19 | def search(params = {}) 20 | @client.call(method: :get, path: 'suppression-list', query_params: params) 21 | end 22 | 23 | # Insert or Update List Entries 24 | # @param recipients [Array] the entries to insert or update 25 | # @note See: https://developers.sparkpost.com/api/suppression-list#suppression-list-bulk-insert-update-put 26 | def create_or_update(recipients) 27 | @client.call(method: :put, path: 'suppression-list', body_values: {recipients: recipients}) 28 | end 29 | 30 | # Retrieve a Recipient Suppression Status 31 | # @param recipient_email [String] the recipient email to retrieve 32 | # @return [Hash] a suppression status result hash object 33 | # @note See: https://developers.sparkpost.com/api/suppression-list#suppression-list-retrieve,-delete-get 34 | def retrieve(recipient_email) 35 | recipient_email = @client.url_encode(recipient_email) 36 | @client.call(method: :get, path: "suppression-list/#{recipient_email}") 37 | end 38 | 39 | # Delete a List Entry 40 | # @param recipient_email [String] the recipient email to delete 41 | # @note See: https://developers.sparkpost.com/api/suppression-list#suppression-list-retrieve,-delete-delete 42 | def delete(recipient_email) 43 | recipient_email = @client.url_encode(recipient_email) 44 | @client.call(method: :delete, path: "suppression-list/#{recipient_email}") 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/relay_webhooks.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /relay-webhooks endpoint 4 | # See: https://developers.sparkpost.com/api/#/reference/relay-webhooks 5 | class RelayWebhooks 6 | attr_accessor :client 7 | 8 | def initialize(client) 9 | @client = client 10 | end 11 | 12 | # Lists your relay webhooks 13 | # @return [Array] a list of Relay Webhook hash objects 14 | # @note See: https://developers.sparkpost.com/api/#/reference/relay-webhooks/create-and-list/list-all-relay-webhooks 15 | def list 16 | @client.call(method: :get, path: 'relay-webhooks') 17 | end 18 | 19 | # Create a relay webhook 20 | # @param values [Hash] the values to create with 21 | # @note See: https://developers.sparkpost.com/api/#/reference/relay-webhooks/create-and-list/create-a-relay-webhook 22 | # @note Example: 23 | # properties = { 24 | # name: "Replies Webhook", 25 | # target: "https://webhooks.customer.example/replies", 26 | # auth_token: "", 27 | # match: { 28 | # protocol: "SMTP", 29 | # domain: "email.example.com" 30 | # } 31 | # } 32 | def create(values) 33 | @client.call(method: :post, path: 'relay-webhooks', body_values: values) 34 | end 35 | 36 | # Retrieve a relay webhook 37 | # @param webhook_id [String] the id to retrieve 38 | # @return [Hash] an Relay Webhook hash object 39 | # @note See: https://developers.sparkpost.com/api/#/reference/relay-webhooks/retrieve-update-and-delete/retrieve-a-relay-webhook 40 | def retrieve(webhook_id) 41 | @client.call(method: :get, path: "relay-webhooks/#{webhook_id}") 42 | end 43 | 44 | # Update a relay webhook 45 | # @param webhook_id [String] the id to retrieve 46 | # @param values [Hash] the values to update the relay webhook with 47 | # @return [Hash] an Relay Webhook hash object 48 | # @note Example: 49 | # properties = { 50 | # name: "New Replies Webhook", 51 | # target: "https://webhook.customer.example/replies" 52 | # } 53 | # @note See: https://developers.sparkpost.com/api/#/reference/relay-webhooks/create-and-list/update-a-relay-webhook 54 | def update(webhook_id, values) 55 | @client.call(method: :put, path: "relay-webhooks/#{webhook_id}", body_values: values) 56 | end 57 | 58 | # Delete a relay webhook 59 | # @param webhook_id [String] the id to retrieve 60 | # @note See: https://developers.sparkpost.com/api/#/reference/relay-webhooks/retrieve-update-and-delete/delete-a-relay-webhook 61 | def delete(webhook_id) 62 | @client.call(method: :delete, path: "relay-webhooks/#{webhook_id}") 63 | end 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/transmissions.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /transmissions endpoint 4 | # See: https://developers.sparkpost.com/api/#/reference/transmissions 5 | class Transmissions 6 | attr_accessor :client 7 | 8 | def initialize(client) 9 | @client = client 10 | end 11 | 12 | # Sends an email message 13 | # @param values [Hash] the values to send with. This can be a complex object depending on the options chosen. 14 | # @param num_rcpt_errors [Integer] limit the number of recipient errors returned. Will default to all 15 | # @returns { results: { total_rejected_recipients: 0, total_accepted_recipients: 1, id: "11668787484950529" } } 16 | # @note See: https://developers.sparkpost.com/api/#/reference/transmissions/create 17 | # @note Example: 18 | # properties = { 19 | # options: { open_tracking: true, click_tracking: true }, 20 | # campaign_id: 'christmas_campaign', 21 | # return_path: 'bounces-christmas-campaign@sp.neekme.com', 22 | # metadata: {user_type: 'students'}, 23 | # substitution_data: { sender: 'Big Store Team' }, 24 | # recipients: [ 25 | # { address: { email: 'yourcustomer@theirdomain.com', name: 'Your Customer' }, 26 | # tags: ['greeting', 'sales'], 27 | # metadata: { place: 'Earth' }, substitution_data: { address: '123 Their Road' } } 28 | # ], 29 | # content: 30 | # { from: { name: 'Your Name', email: 'you@yourdomain.com' }, 31 | # subject: 'I am a test email', 32 | # reply_to: 'Sales ', 33 | # headers: { 'X-Customer-CampaignID' => 'christmas_campaign' }, 34 | # text: 'Hi from {{sender}} ... this is a test, and here is your address {{address}}', 35 | # html: '

Hi from {{sender}}This is a test

' 36 | # } 37 | # } 38 | def create(values, num_rcpt_errors = nil) 39 | query_params = num_rcpt_errors.nil? ? {} : { num_rcpt_errors: num_rcpt_errors } 40 | @client.call(method: :post, path: 'transmissions', body_values: values, query_values: query_params) 41 | end 42 | 43 | # Sends an email message 44 | # @param campaign_id [String] limit results to this Campaign ID 45 | # @param template_id [String] limit results to this Template ID 46 | # @returns [ { "content": { "template_id": "winter_sale" }, "id": "11713562166689858", 47 | # "campaign_id": "thanksgiving", "description": "", "state": "submitted" } ] 48 | # @note See: https://developers.sparkpost.com/api/#/reference/transmissions/list 49 | def list(campaign_id = nil, template_id = nil) 50 | query_params = {} 51 | query_params[:campaign_id] = campaign_id if campaign_id 52 | query_params[:template_id] = template_id if template_id 53 | @client.call(method: :get, path: 'transmissions', query_values: query_params) 54 | end 55 | 56 | # send_message to be reserved as a 'quick' helper method to avoid using hash for Create 57 | # alias_method :send_message, :create 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/webhooks.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /webhooks endpoint 4 | # @note Example webhook 5 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks 6 | class Webhooks 7 | attr_accessor :client 8 | 9 | def initialize(client) 10 | @client = client 11 | end 12 | 13 | # List currently extant webhooks 14 | # @return [Array] a list of Webhook hash objects 15 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/list 16 | def list(timezone = nil) 17 | query_params = timezone.nil? ? {} : { timezone: timezone } 18 | @client.call(method: :get, path: 'webhooks', query_values: query_params) 19 | end 20 | 21 | # Create a webhook 22 | # @param values [Hash] the values to create the webhook with 23 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/create 24 | def create(values) 25 | @client.call(method: :post, path: 'webhooks', body_values: values) 26 | end 27 | 28 | # Retrieve details about a webhook by specifying its id 29 | # @param id [String] the ID of the webhook 30 | # @return [Hash] an Webhook hash object 31 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/retrieve 32 | def retrieve(id) 33 | @client.call(method: :get, path: "webhooks/#{id}") 34 | end 35 | 36 | # Update a Webhook by its ID 37 | # @param id [String] the ID of the webhook 38 | # @param values [Hash] the values to update the webhook with 39 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/update-and-delete 40 | def update(id, values) 41 | @client.call(method: :put, path: "webhooks/#{id}", body_values: values) 42 | end 43 | 44 | # Validates a Webhook by sending an example message event batch from the Webhooks API to the target URL 45 | # @param id [String] the ID of the webhook 46 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/validate 47 | def validate(id) 48 | @client.call(method: :post, path: "webhooks/#{id}/validate") 49 | end 50 | 51 | # Batch status information 52 | # @param id [String] the ID of the webhook 53 | # @return [Array] a list of status hash objects 54 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/batch-status 55 | def batch_status(id, limit = nil) 56 | query_params = limit.nil? ? {} : { limit: limit } 57 | @client.call(method: :get, path: "webhooks/#{id}/batch-status", query_values: query_params) 58 | end 59 | 60 | # Returns sample event data 61 | # @param events [String] Event types for which to get a sample payload 62 | # @return [Array] a list of sample event hash objects 63 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/events-samples 64 | def samples(events = nil) 65 | query_params = events.nil? ? {} : { events: events } 66 | @client.call(method: :get, path: 'webhooks/events/samples', query_values: query_params) 67 | end 68 | 69 | # Delete a webhook 70 | # @param id [String] the ID 71 | # @note See: https://developers.sparkpost.com/api/#/reference/webhooks/update-and-delete 72 | def delete(id) 73 | @client.call(method: :delete, path: "webhooks/#{id}") 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/sending_domains.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /sending-domains endpoint 4 | # @note Example sending domain 5 | # { "domain": "example1.com", "tracking_domain": "click.example1.com", 6 | # "status": { "ownership_verified": true, "spf_status": "valid", "abuse_at_status": "valid", 7 | # "abuse_at_status": "valid", "dkim_status": "valid", "compliance_status": "valid", "postmaster_at_status": "valid" } } 8 | # @note See: https://developers.sparkpost.com/api/#/reference/sending-domains 9 | class SendingDomains 10 | attr_accessor :client 11 | 12 | def initialize(client) 13 | @client = client 14 | end 15 | 16 | # Lists your sending domains 17 | # @return [Array] a list of Sending Domain hash objects 18 | # @note See: https://developers.sparkpost.com/api/#/reference/sending-domains/create-and-list/list-all-sending-domains 19 | def list 20 | @client.call(method: :get, path: 'sending-domains') 21 | end 22 | 23 | # Create a sending domain 24 | # @param domain_name [String] the domain name to create 25 | # @param tracking_domain [String] the domain name to track this domain against 26 | # @note See: https://developers.sparkpost.com/api/#/reference/sending-domains/create-and-list 27 | def create(values) 28 | @client.call(method: :post, path: 'sending-domains', body_values: values) 29 | end 30 | 31 | # Retrieve a sending domain 32 | # @param domain_name [String] the domain name to retrieve 33 | # @return [Hash] an Sending Domain hash object 34 | # @note See: https://developers.sparkpost.com/api/#/reference/sending-domains/retrieve-update-and-delete 35 | def retrieve(domain_name) 36 | domain_name = @client.url_encode(domain_name) 37 | @client.call(method: :get, path: "sending-domains/#{domain_name}") 38 | end 39 | 40 | # Update a Sending Domain by its domain name 41 | # @param domain_name [String] the domain to update 42 | # @param values [Hash] the values to update the sending domain with 43 | # 44 | # @note See: https://developers.sparkpost.com/api/#/reference/sending-domains/retrieve-update-and-delete 45 | def update(domain_name, values) 46 | domain_name = @client.url_encode(domain_name) 47 | @client.call(method: :put, path: "sending-domains/#{domain_name}", body_values: values) 48 | end 49 | 50 | # Verify a Sending Domain by its domain name 51 | # @param domain_name [String] the domain to verify 52 | # @param values [Hash] the values specifying how to verify the domain 53 | # Including the fields "dkim_verify" and/or "spf_verify" in the request initiates a check against the associated DNS record 54 | # type for the specified sending domain.Including the fields "postmaster_at_verify" and/or "abuse_at_verify" in the request 55 | # results in an email sent to the specified sending domain's postmaster@ and/or abuse@ mailbox where a verification link can 56 | # be clicked.Including the fields "postmaster_at_token" and/or "abuse_at_token" in the request initiates a check of the provided 57 | # token(s) against the stored token(s) for the specified sending domain. 58 | # 59 | # @note See: https://developers.sparkpost.com/api/#/reference/sending-domains/verify 60 | def verify(domain_name, values) 61 | domain_name = @client.url_encode(domain_name) 62 | @client.call(method: :post, path: "sending-domains/#{domain_name}/verify", body_values: values) 63 | end 64 | 65 | # Delete a sending domain 66 | # @param domain_name [String] the domain name to delete 67 | # @note See: https://developers.sparkpost.com/api/#/reference/sending-domains/retrieve-update-and-delete 68 | def delete(domain_name) 69 | domain_name = @client.url_encode(domain_name) 70 | @client.call(method: :delete, path: "sending-domains/#{domain_name}") 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/templates.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /templates endpoint 4 | # @note See: https://developers.sparkpost.com/api/#/reference/templates 5 | # @note Sample Template 6 | # { "id"=>"102293692714480130", "name"=>"Summer Sale!", "description"=>"", "published"=>false, "options"=>{}, 7 | # "last_update_time"=>"2016-03-02T22:49:23+00:00", 8 | # "content"=>{"from"=>"marketing@neekme.com", "subject"=>"Summer deals", "html"=>"Check out these deals!"} } 9 | class Templates 10 | attr_accessor :client 11 | 12 | def initialize(client) 13 | @client = client 14 | end 15 | 16 | # Lists the most recent version of each template in your account. 17 | # @return [Array] a list of Template hash objects 18 | # @note See: https://developers.sparkpost.com/api/#/reference/templates/create-and-list 19 | def list 20 | @client.call(method: :get, path: 'templates') 21 | end 22 | 23 | # Create a template by providing values for the template object. 24 | # @param values [Hash] containing the properties. At a minimum, the "name" and "content" 25 | # fields are required, where content must contain the "from", "subject", and at 26 | # least one of "html" or "text" fields. 27 | # @return [boolean] true if success 28 | # @note See: https://developers.sparkpost.com/api/#/reference/templates/create-and-list 29 | def create(values) 30 | @client.call(method: :post, path: 'templates', body_values: values) 31 | end 32 | 33 | # Retrieve a Template by its ID 34 | # @param id [String] the Unique Template ID to retrieve 35 | # @param draft [boolean] If true, returns the most recent draft template. 36 | # If false, returns the most recent published template. 37 | # If not provided, returns the most recent template version regardless of draft or published. 38 | # @return [Hash] the Template object 39 | # @note https://developers.sparkpost.com/api/#/reference/templates/retrieve 40 | def retrieve(id, draft = nil) 41 | path = "templates/#{id}" 42 | query_params = draft.nil? ? {} : { draft: draft } 43 | @client.call(method: :get, path: path, query_values: query_params) 44 | end 45 | 46 | # Update a Template by its ID 47 | # @param id [String] the Unique Template ID to update 48 | # @param values [Hash] the values to update the template with 49 | # @param update_published [boolean] If true, directly overwrite the existing published template. If false, create a new draft. 50 | # If this template isn't yet published, setting to 'true' will result in a NotFound error 51 | # 52 | # @note See: https://developers.sparkpost.com/api/#/reference/templates/update 53 | def update(id, values, update_published = false) 54 | @client.call(method: :put, path: "templates/#{id}", body_values: values, query_values: { update_published: update_published }) 55 | end 56 | 57 | # Preview a Template by its ID 58 | # @param id [String] the Unique Template ID to preview 59 | # @param substitutions [Hash] the values to update the template with. Must contain a key 'substitution_data' 60 | # { "substitution_data" => { "name" => "Natalie", "age" => 35, "member" => true } 61 | # @param draft [boolean] If true, returns the most recent draft template. 62 | # If false, returns the most recent published template. 63 | # If not provided, returns the most recent template version regardless of draft or published. 64 | # 65 | # @note See: https://developers.sparkpost.com/api/#/reference/templates/preview 66 | def preview(id, substitutions, draft = nil) 67 | query_params = draft.nil? ? {} : { draft: draft } 68 | @client.call(method: :post, path: "templates/#{id}/preview", body_values: substitutions, query_values: query_params) 69 | end 70 | 71 | # Delete a Template by its ID 72 | # @param id [String] the Unique Template ID to delete 73 | # 74 | # @note See: https://developers.sparkpost.com/api/#/reference/templates/delete 75 | def delete(id) 76 | @client.call(method: :delete, path: "templates/#{id}") 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /spec/simple_spark/client_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SimpleSpark::Client do 4 | describe :initialize do 5 | it 'will raise when no API key provided' do 6 | expect { SimpleSpark::Client.new }.to raise_error(SimpleSpark::Exceptions::InvalidConfiguration, 'You must provide a SparkPost API key') 7 | end 8 | 9 | context 'defaults' do 10 | let(:client) { SimpleSpark::Client.new(api_key: 'mykey') } 11 | specify { expect(client.instance_variable_get(:@api_key)).to eq('mykey') } 12 | specify { expect(client.instance_variable_get(:@api_host)).to eq('https://api.sparkpost.com') } 13 | specify { expect(client.instance_variable_get(:@base_path)).to eq('/api/v1/') } 14 | specify { expect(client.instance_variable_get(:@session).class).to eq(Excon::Connection) } 15 | specify { expect(client.instance_variable_get(:@debug)).to eq(false) } 16 | specify { expect(client.instance_variable_get(:@subaccount_id)).to eq(nil) } 17 | end 18 | 19 | it 'will use the API key from the ENV var' do 20 | with_modified_env SPARKPOST_API_KEY: 'mykey' do 21 | expect(SimpleSpark::Client.new.instance_variable_get(:@api_key)).to eq('mykey') 22 | end 23 | end 24 | 25 | it 'will use the base_path provided' do 26 | expect(SimpleSpark::Client.new(api_key: 'mykey', base_path: 'base').instance_variable_get(:@base_path)).to eq('base') 27 | end 28 | 29 | it 'will use the debug option provided' do 30 | expect(SimpleSpark::Client.new(api_key: 'mykey', debug: true).instance_variable_get(:@debug)).to eq(true) 31 | end 32 | 33 | context 'using the subaccount id provided' do 34 | let(:subaccount_id) { 'my_subaccount_id' } 35 | let(:client) { SimpleSpark::Client.new(api_key: 'mykey', subaccount_id: subaccount_id) } 36 | specify { expect(client.instance_variable_get(:@subaccount_id)).to eq(subaccount_id) } 37 | specify { expect(client.headers).to include('X-MSYS-SUBACCOUNT' => subaccount_id) } 38 | end 39 | 40 | context 'using the headers option provided' do 41 | let(:headers) { { x: 'y' } } 42 | let(:client) { SimpleSpark::Client.new(api_key: 'mykey', headers: headers) } 43 | specify { expect(client.instance_variable_get(:@headers)).to eq(headers) } 44 | specify { expect(client.headers).to include(headers) } 45 | 46 | it 'specified headers will override default constructed ones' do 47 | client = SimpleSpark::Client.new(api_key: 'mykey', subaccount_id: 'old', headers: { 'X-MSYS-SUBACCOUNT' => 'new' }) 48 | expect(client.headers['X-MSYS-SUBACCOUNT']).to eq('new') 49 | end 50 | end 51 | 52 | it 'will raise when headers is not a Hash' do 53 | expect { SimpleSpark::Client.new(api_key: 'mykey', headers: 'wrong') }.to raise_error(SimpleSpark::Exceptions::InvalidConfiguration, 'The headers options provided must be a valid Hash') 54 | end 55 | 56 | context 'endpoints' do 57 | let(:client) { SimpleSpark::Client.new(api_key: 'mykey') } 58 | 59 | context 'metrics' do 60 | specify { expect(client.metrics.class).to eq(SimpleSpark::Endpoints::Metrics) } 61 | end 62 | 63 | context 'subaccounts' do 64 | specify { expect(client.subaccounts.class).to eq(SimpleSpark::Endpoints::Subaccounts) } 65 | end 66 | 67 | context 'inbound_domains' do 68 | specify { expect(client.inbound_domains.class).to eq(SimpleSpark::Endpoints::InboundDomains) } 69 | end 70 | 71 | context 'message_events' do 72 | specify { expect(client.message_events.class).to eq(SimpleSpark::Endpoints::MessageEvents) } 73 | end 74 | 75 | context 'relay_webhooks' do 76 | specify { expect(client.relay_webhooks.class).to eq(SimpleSpark::Endpoints::RelayWebhooks) } 77 | end 78 | 79 | context 'sending_domains' do 80 | specify { expect(client.sending_domains.class).to eq(SimpleSpark::Endpoints::SendingDomains) } 81 | end 82 | 83 | context 'templates' do 84 | specify { expect(client.templates.class).to eq(SimpleSpark::Endpoints::Templates) } 85 | end 86 | 87 | context 'transmissions' do 88 | specify { expect(client.transmissions.class).to eq(SimpleSpark::Endpoints::Transmissions) } 89 | end 90 | 91 | context 'webhooks' do 92 | specify { expect(client.webhooks.class).to eq(SimpleSpark::Endpoints::Webhooks) } 93 | end 94 | 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /lib/simple_spark/client.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'excon' 3 | require 'json' 4 | require 'logger' 5 | 6 | module SimpleSpark 7 | class Client 8 | attr_reader :logger 9 | 10 | def initialize(opts = {}) 11 | @api_key = opts[:api_key] || ENV['SPARKPOST_API_KEY'] 12 | @api_host = opts[:api_host] || 'https://api.sparkpost.com' 13 | @base_path = opts[:base_path] || '/api/v1/' 14 | @subaccount_id = opts[:subaccount_id] 15 | @headers = opts[:headers] 16 | 17 | @logger = opts[:logger] || SimpleSpark::Client.default_logger 18 | 19 | fail Exceptions::InvalidConfiguration.new, 'You must provide a SparkPost API key' unless @api_key 20 | fail Exceptions::InvalidConfiguration.new, 'You must provide a SparkPost API host' unless @api_host # this should never occur unless the default above is changed 21 | fail Exceptions::InvalidConfiguration.new, 'You must provide a SparkPost base path' unless @base_path # this should never occur unless the default above is changed 22 | fail Exceptions::InvalidConfiguration.new, 'The headers options provided must be a valid Hash' if @headers && !@headers.is_a?(Hash) 23 | 24 | rails_development = true & defined?(Rails) && Rails.env.development? 25 | 26 | @debug = opts[:debug].nil? ? rails_development : opts[:debug] 27 | 28 | # switch debug params, allow for old and new parameters and supress Excon warning 29 | debug_options = Excon::VALID_REQUEST_KEYS.any? { |k| k == :debug } ? { debug: @debug } : { debug_request: @debug, debug_response: @debug } 30 | 31 | @session = Excon.new(@api_host, debug_options) 32 | end 33 | 34 | def call(opts) 35 | method = opts[:method] 36 | path = opts[:path] 37 | body_values = opts[:body_values] || {} 38 | query_params = opts[:query_values] || {} 39 | extract_results = opts[:extract_results].nil? ? true : opts[:extract_results] 40 | 41 | fail Exceptions::InvalidConfiguration.new(method: method), 'Only GET, POST, PUT and DELETE are supported' unless [:get, :post, :put, :delete].include?(method) 42 | 43 | path = "#{@base_path}#{path}" 44 | params = { path: path, headers: headers } 45 | params[:body] = JSON.generate(body_values) unless body_values.empty? 46 | params[:query] = query_params unless query_params.empty? 47 | 48 | if @debug 49 | logger.debug("Calling #{method}") 50 | logger.debug(params) 51 | end 52 | 53 | response = @session.send(method.to_s, params) 54 | 55 | if @debug 56 | logger.debug("Response #{response.status}") 57 | logger.debug(response) 58 | end 59 | 60 | fail Exceptions::GatewayTimeoutExceeded, 'Received 504 from SparkPost API' if response.status == 504 61 | 62 | process_response(response, extract_results) 63 | 64 | rescue Excon::Errors::Timeout 65 | raise Exceptions::GatewayTimeoutExceeded 66 | end 67 | 68 | def process_response(response, extract_results) 69 | logger.warn('Response had an empty body') if (response.body.nil? || response.body == '') && response.status != 204 70 | return {} if response.status == 204 || response.body.nil? || response.body == '' 71 | 72 | response_body = JSON.parse(response.body) 73 | if response_body['errors'] 74 | Exceptions::Error.fail_with_exception_for_status(response.status, response_body['errors']) 75 | else 76 | if extract_results 77 | response_body['results'] ? response_body['results'] : {} 78 | else 79 | response_body 80 | end 81 | end 82 | end 83 | 84 | # Copied from http://apidock.com/ruby/ERB/Util/url_encode 85 | def url_encode(s) 86 | s.to_s.dup.force_encoding('ASCII-8BIT').gsub(/[^a-zA-Z0-9_\-.]/) { sprintf('%%%02X', $&.unpack('C')[0]) } 87 | end 88 | 89 | def headers 90 | defaults = { 91 | 'User-Agent' => 'simple_spark/' + VERSION, 92 | 'Content-Type' => 'application/json', 93 | 'Accept' => 'application/json', 94 | 'Authorization' => @api_key 95 | } 96 | defaults.merge!('X-MSYS-SUBACCOUNT' => @subaccount_id) if @subaccount_id 97 | defaults.merge!(@headers) if @headers 98 | defaults 99 | end 100 | 101 | def self.default_logger 102 | logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT) 103 | logger.progname = 'simple_spark' if logger.respond_to?(:progname=) 104 | logger 105 | end 106 | 107 | def metrics 108 | Endpoints::Metrics.new(self) 109 | end 110 | 111 | def subaccounts 112 | Endpoints::Subaccounts.new(self) 113 | end 114 | 115 | def inbound_domains 116 | Endpoints::InboundDomains.new(self) 117 | end 118 | 119 | def sending_domains 120 | Endpoints::SendingDomains.new(self) 121 | end 122 | 123 | def templates 124 | Endpoints::Templates.new(self) 125 | end 126 | 127 | def transmissions 128 | Endpoints::Transmissions.new(self) 129 | end 130 | 131 | def message_events 132 | Endpoints::MessageEvents.new(self) 133 | end 134 | 135 | def webhooks 136 | Endpoints::Webhooks.new(self) 137 | end 138 | 139 | def relay_webhooks 140 | Endpoints::RelayWebhooks.new(self) 141 | end 142 | 143 | def suppression_list 144 | Endpoints::SuppressionList.new(self) 145 | end 146 | end 147 | end 148 | -------------------------------------------------------------------------------- /lib/simple_spark/endpoints/metrics.rb: -------------------------------------------------------------------------------- 1 | module SimpleSpark 2 | module Endpoints 3 | # Provides access to the /metrics endpoint 4 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics 5 | class Metrics 6 | attr_accessor :client 7 | 8 | def initialize(client) 9 | @client = client 10 | end 11 | 12 | # The Metrics API is designed for discoverability of child links. Calling the API root displays a list of URIs that exists within the Metrics API. 13 | # @return [Hash] containg a Metrics hash, the 'links' key will contain the links 14 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/metrics-discoverability-links 15 | def discoverability_links 16 | @client.call(method: :get, path: 'metrics', extract_results: false) 17 | end 18 | 19 | # Deliverability Metrics Summary 20 | # @param values [Hash] the values to query with 21 | # @note dates from and need to be sent using strftime('%Y-%m-%dT%H:%M'), for convenience if provided as Time, Date or DateTime objects they will be automatically converted 22 | # @return [Hash] containg a Metrics hash, the 'results' key will contain the metrics, the 'links' key will contain discoverability links 23 | # @note Example: 24 | # client.metrics.deliverability_metrics_summary(from: '2013-04-20T07:12', to: '2018-04-20T07:12', metrics: 'count_accepted', timezone: 'America/New_York') 25 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/discoverability-links/deliverability-metrics-summary 26 | def deliverability_metrics_summary(values) 27 | format_date_time_values(values) 28 | @client.call(method: :get, path: 'metrics/deliverability', query_values: values, extract_results: false) 29 | end 30 | 31 | # Deliverability Metrics By Domain 32 | # @param values [Hash] the values to query with 33 | # @note dates from and need to be sent using strftime('%Y-%m-%dT%H:%M'), for convenience if provided as Time, Date or DateTime objects they will be automatically converted 34 | # @return [Array] containg Metrics results i.e. { "count_accepted": 66, "domain": "gmail.com" } 35 | # @note Example: 36 | # client.metrics.deliverability_metrics_by_domain(from: '2013-04-20T07:12', to: '2018-04-20T07:12', metrics: 'count_accepted', timezone: 'America/New_York', domains: 'gmail.com') 37 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/deliverability-metrics/deliverability-metrics-by-domain 38 | def deliverability_metrics_by_domain(values) 39 | format_date_time_values(values) 40 | @client.call(method: :get, path: 'metrics/deliverability/domain', query_values: values) 41 | end 42 | 43 | # Deliverability Metrics By Sending Domain 44 | # @param values [Hash] the values to query with 45 | # @note dates from and need to be sent using strftime('%Y-%m-%dT%H:%M'), for convenience if provided as Time, Date or DateTime objects they will be automatically converted 46 | # @return [Array] containg Metrics results i.e. { "count_accepted": 66, "sending_domain": "gmail.com" } 47 | # @note Example: 48 | # client.metrics.deliverability_metrics_by_sending_domain(from: '2013-04-20T07:12', to: '2018-04-20T07:12', metrics: 'count_accepted', timezone: 'America/New_York', sending_domains: 'mydomain.com') 49 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/deliverability-metrics/deliverability-metrics-by-sending-domain 50 | def deliverability_metrics_by_sending_domain(values) 51 | format_date_time_values(values) 52 | @client.call(method: :get, path: 'metrics/deliverability/sending-domain', query_values: values) 53 | end 54 | 55 | # Deliverability Metrics By Campaign 56 | # @param values [Hash] the values to query with 57 | # @note dates from and need to be sent using strftime('%Y-%m-%dT%H:%M'), for convenience if provided as Time, Date or DateTime objects they will be automatically converted 58 | # @return [Array] containg Metrics results i.e. { "count_accepted": 66, "campaign_id": "Summer Sale" } 59 | # @note Example: 60 | # client.metrics.deliverability_metrics_by_campaign(from: '2013-04-20T07:12', to: '2018-04-20T07:12', metrics: 'count_accepted', timezone: 'America/New_York', campaigns: 'Summer Sale') 61 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/deliverability-metrics/deliverability-metrics-by-campaign 62 | def deliverability_metrics_by_campaign(values) 63 | format_date_time_values(values) 64 | @client.call(method: :get, path: 'metrics/deliverability/campaign', query_values: values) 65 | end 66 | 67 | # Deliverability Metrics By Subaccount 68 | # @param values [Hash] the values to query with 69 | # @note dates from and need to be sent using strftime('%Y-%m-%dT%H:%M'), for convenience if provided as Time, Date or DateTime objects they will be automatically converted 70 | # @return [Array] containg Metrics results i.e. { "count_accepted": 66, "subaccount_id": "acc123" } 71 | # @note Example: 72 | # client.metrics.deliverability_metrics_by_subaccount(from: '2013-04-20T07:12', to: '2018-04-20T07:12', metrics: 'count_accepted', timezone: 'America/New_York', subaccounts: 'acc123') 73 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/deliverability-metrics/deliverability-metrics-by-subaccount 74 | def deliverability_metrics_by_subaccount(values) 75 | format_date_time_values(values) 76 | @client.call(method: :get, path: 'metrics/deliverability/subaccount', query_values: values) 77 | end 78 | 79 | # Deliverability Metrics By Template 80 | # @param values [Hash] the values to query with 81 | # @note dates from and need to be sent using strftime('%Y-%m-%dT%H:%M'), for convenience if provided as Time, Date or DateTime objects they will be automatically converted 82 | # @return [Array] containg Metrics results i.e. { "count_accepted": 66, "template": "My Template" } 83 | # @note Example: 84 | # client.metrics.deliverability_metrics_by_template(from: '2013-04-20T07:12', to: '2018-04-20T07:12', metrics: 'count_accepted', timezone: 'America/New_York', subaccounts: 'acc123') 85 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/deliverability-metrics/deliverability-metrics-by-template 86 | def deliverability_metrics_by_template(values) 87 | format_date_time_values(values) 88 | @client.call(method: :get, path: 'metrics/deliverability/template', query_values: values) 89 | end 90 | 91 | # Time Series 92 | # @param values [Hash] the values to query with 93 | # @note dates from and need to be sent using strftime('%Y-%m-%dT%H:%M'), for convenience if provided as Time, Date or DateTime objects they will be automatically converted 94 | # @return [Array] containg Metrics results with time stamps i.e. [{"count_targeted"=>0, "ts"=>"2011-06-01T00:00:00+00:00"}] 95 | # @note Example: 96 | # client.metrics.deliverability_time_series(from: '2013-04-20T07:12', to: '2018-04-20T07:12', metrics: 'count_accepted', timezone: 'America/New_York', precision: 'day') 97 | # @note See: https://developers.sparkpost.com/api/#/reference/metrics/time-series/time-series-metrics 98 | def deliverability_time_series(values) 99 | format_date_time_values(values) 100 | @client.call(method: :get, path: 'metrics/deliverability/time-series', query_values: values) 101 | end 102 | 103 | private 104 | 105 | def format_date_time_values(values) 106 | values.keys.each { |k| values[k] = values[k].strftime('%Y-%m-%dT%H:%M') if values[k].respond_to?(:strftime) } 107 | end 108 | end 109 | end 110 | end 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleSpark 2 | 3 | [![Build Status](https://travis-ci.org/leadmachineapp/simple_spark.png?branch=master)](https://travis-ci.org/leadmachineapp/simple_spark) [![Gem Version](https://badge.fury.io/rb/simple_spark.svg)](https://badge.fury.io/rb/simple_spark) 4 | 5 | ## Update from SparkPost 6 | 7 | Posted in the SparkPost Announcements channel on 17th May 2016 8 | 9 | > Due to incredible support and contributions from the community, we will be discontinuing support of the official SparkPost ruby client library as of May 17, 2016. 10 | 11 | As SparkPost have now stopped development on their own gem, and have recommended this one as being a better alternative, bumping version to 1.0.0 - the code has been running in production for a while now and seems stable and near feature complete. 12 | 13 | ## Installation 14 | 15 | Add this line to your application's Gemfile: 16 | 17 | ```ruby 18 | gem 'simple_spark' 19 | ``` 20 | 21 | And then execute: 22 | 23 | ``` 24 | $ bundle 25 | ``` 26 | 27 | Or install it yourself as: 28 | 29 | ``` 30 | $ gem install simple_spark 31 | ``` 32 | 33 | ## Usage 34 | 35 | ### Why? 36 | 37 | The official gem was somewhat lacking in functionality, though with the demise of Mandrill it seems SparkPost decided to restart development on it, they have now abandoned that as of 17th May 2016 38 | 39 | As we would have to write wrappers around all the functions we would need for our app to use SparkPost anyway, it seemed much easier to write the wrapper as a gem and allow others to use it too. 40 | 41 | ### Status 42 | 43 | Breaking change: initialising the client is now done with a hash instead of with ordered parameters, as there were getting to be too many after supporting Subaccounts and user specified headers 44 | 45 | ## Endpoints 46 | 47 | ### Creating a Client 48 | 49 | First you need to ensure you are requiring the library 50 | 51 | ```ruby 52 | require 'simple_spark' 53 | ``` 54 | 55 | The simplest version of the client is to just provide your [API key from SparkPost](https://app.sparkpost.com/account/credentials) 56 | 57 | ```ruby 58 | simple_spark = SimpleSpark::Client.new(api_key: 'your_api_key') 59 | ``` 60 | 61 | You can also use ENV vars to configure the key, setting ENV['SPARKPOST_API_KEY'] will allow you to just use 62 | 63 | ```ruby 64 | simple_spark = SimpleSpark::Client.new 65 | ``` 66 | 67 | You can also override the other options if you need to in advanced scenarios, the full signature is (api_key, api_host, base_path, debug), i.e. 68 | 69 | ```ruby 70 | simple_spark = SimpleSpark::Client.new(api_key: 'your_api_key', api_host: 'https://api.sparkpost.com', base_path: '/api/v1/', debug: false, subaccount_id: 'my_subaccount') 71 | ``` 72 | 73 | #### Debug 74 | 75 | Setting debug to true will cause [Excon](https://github.com/excon/excon) to output full debug information to the log. 76 | 77 | This will default to true if you are running under Rails and are in a development environment, otherwise it will default to false (setting other values to nil will cause them to use their defaults) 78 | 79 | You can also pass a Logger into the client options to have SimpleSpark log there. By default Rails.logger will be used when runnign under Rails, and STDOUT will be used otherwise 80 | 81 | ```ruby 82 | simple_spark = SimpleSpark::Client.new(api_key: 'your_api_key', debug: true, logger: Rails.logger) 83 | ``` 84 | 85 | #### Subaccounts 86 | 87 | By setting subaccount_id on your client you are telling Simple Spark to use that subaccount for all calls made on this instance of the client. 88 | 89 | Not all Sparkpost calls support the Subaccount feature, and their API will throw an unauthorized error if you use a subaccount_id on an unsupported call. Depending on your code this may mean you need to instantiate two instances of the Simple Spark client in your code, one for subaccount calls, and one for other calls. This is a less than ideal solution, but due to the rapid pace of Sparkpost development on their API this is the option that causes least dependency up Simple Spark to be updated as their API is. 90 | 91 | #### Headers 92 | 93 | Should you have any need to override the headers that are sent by default, then you can specify headers as an option. The headers specified here will override any of the generated headers that the library creates. In normal operation there should be no reason to use this option, but it is provided for convenience and to allow for Sparkpost updating their API in any unexpected way. 94 | 95 | ```ruby 96 | simple_spark = SimpleSpark::Client.new(api_key: 'your_api_key', headers: { 'NewSparkpostHeader' => 'hello'}) 97 | ``` 98 | 99 | ### Exceptions 100 | 101 | SimpleSpark wraps all the common errors from the SparkPost API 102 | 103 | If the API takes too long to respond (times out in Excon) a GatewayTimeoutExceeded will be raised 104 | 105 | Status 400 raises Exceptions::BadRequest 106 | 107 | Status 404 raises Exceptions::NotFound 108 | 109 | Status 422 raises Exceptions::UnprocessableEntity 110 | 111 | Status 420/429 raises Exceptions::ThrottleLimitExceeded 112 | 113 | Other response status codes raise Exceptions::UnprocessableEntity 114 | 115 | In some cases it is possible to send too fast for the API (apparently) to handle , in this case the SparkPost API returns a 504 status with an empty body. This is raised by SimpleSpark as Exceptions::GatewayTimeoutExceeded 116 | 117 | ### Metrics 118 | 119 | #### Discoverability Links 120 | 121 | ```ruby 122 | simple_spark.metrics.discoverability_links 123 | ``` 124 | 125 | see SparkPost API Documentation 126 | 127 | #### Deliverability Metrics Summary 128 | 129 | Summary of metrics 130 | 131 | ```ruby 132 | properties = { 133 | from: '2013-04-20T07:12', 134 | to: '2018-04-20T07:12', 135 | metrics: 'count_accepted', 136 | timezone: 'America/New_York' 137 | } 138 | simple_spark.metrics.deliverability_metrics_summary(properties) 139 | ``` 140 | 141 | see SparkPost API Documentation 142 | 143 | #### Deliverability Metrics by Domain 144 | 145 | Metrics grouped by Domain 146 | 147 | ```ruby 148 | properties = { 149 | from: '2013-04-20T07:12', 150 | to: '2018-04-20T07:12', 151 | metrics: 'count_accepted', 152 | timezone: 'America/New_York' 153 | } 154 | simple_spark.metrics.deliverability_metrics_by_domain(properties) 155 | ``` 156 | 157 | see SparkPost API Documentation 158 | 159 | #### Deliverability Metrics by Sending Domain 160 | 161 | Metrics grouped by Sending Domain 162 | 163 | ```ruby 164 | properties = { 165 | from: '2013-04-20T07:12', 166 | to: '2018-04-20T07:12', 167 | metrics: 'count_accepted', 168 | timezone: 'America/New_York' 169 | } 170 | simple_spark.metrics.deliverability_metrics_by_sending_domain(properties) 171 | ``` 172 | 173 | see SparkPost API Documentation 174 | 175 | #### Deliverability Metrics by Subaccount 176 | 177 | Metrics grouped by Subaccount 178 | 179 | ```ruby 180 | properties = { 181 | from: '2013-04-20T07:12', 182 | to: '2018-04-20T07:12', 183 | metrics: 'count_accepted', 184 | timezone: 'America/New_York' 185 | } 186 | simple_spark.metrics.deliverability_metrics_by_subaccount(properties) 187 | ``` 188 | 189 | see SparkPost API Documentation 190 | 191 | #### Deliverability Metrics by Campaign 192 | 193 | Metrics grouped by Campaign 194 | 195 | ```ruby 196 | properties = { 197 | from: '2013-04-20T07:12', 198 | to: '2018-04-20T07:12', 199 | metrics: 'count_accepted', 200 | timezone: 'America/New_York' 201 | } 202 | simple_spark.metrics.deliverability_metrics_by_campaign(properties) 203 | ``` 204 | 205 | see SparkPost API Documentation 206 | 207 | #### Deliverability Metrics by Template 208 | 209 | Metrics grouped by Template 210 | 211 | ```ruby 212 | properties = { 213 | from: '2013-04-20T07:12', 214 | to: '2018-04-20T07:12', 215 | metrics: 'count_accepted', 216 | timezone: 'America/New_York' 217 | } 218 | simple_spark.metrics.deliverability_metrics_by_template(properties) 219 | ``` 220 | 221 | see SparkPost API Documentation 222 | 223 | #### Deliverability Metrics as Time Series 224 | 225 | Metrics across a Time Series 226 | 227 | ```ruby 228 | properties = { 229 | from: '2013-04-20T07:12', 230 | to: '2018-04-20T07:12', 231 | metrics: 'count_accepted', 232 | timezone: 'America/New_York', 233 | precision: 'day' 234 | } 235 | simple_spark.metrics.deliverability_time_series(properties) 236 | ``` 237 | 238 | Returns an array of metrics with time stamps: 239 | 240 | ```ruby 241 | [{ "count_targeted"=>2, "ts"=>"2011-06-01T00:00:00+00:00" }, { "count_targeted"=>3, "ts"=>"2011-06-02T00:00:00+00:00" }] 242 | ``` 243 | 244 | see SparkPost API Documentation 245 | 246 | ### Transmissions 247 | 248 | #### List 249 | 250 | List all Transmissions 251 | 252 | When messages are sent the Transmission will be deleted, so this will only return transmissions that are about to be sent or are scheduled for the future 253 | 254 | ```ruby 255 | simple_spark.transmissions.list 256 | ``` 257 | 258 | see SparkPost API Documentation 259 | 260 | #### Create 261 | 262 | Create a new Transmission 263 | 264 | ```ruby 265 | properties = { 266 | options: { open_tracking: true, click_tracking: true }, 267 | campaign_id: 'christmas_campaign', 268 | return_path: 'bounces-christmas-campaign@sp.neekme.com', 269 | metadata: {user_type: 'students'}, 270 | substitution_data: { sender: 'Big Store Team' }, 271 | recipients: [ 272 | { address: { email: 'yourcustomer@theirdomain.com', name: 'Your Customer' }, 273 | tags: ['greeting', 'sales'], 274 | metadata: { place: 'Earth' }, substitution_data: { address: '123 Their Road' } } 275 | ], 276 | content: 277 | { from: { name: 'Your Name', email: 'you@yourdomain.com' }, 278 | subject: 'I am a test email', 279 | reply_to: 'Sales ', 280 | headers: { 'X-Customer-CampaignID' => 'christmas_campaign' }, 281 | text: 'Hi from {{sender}} ... this is a test, and here is your address {{address}}', 282 | html: '

Hi from {{sender}}This is a test

' 283 | } 284 | } 285 | 286 | simple_spark.transmissions.create(properties) 287 | ``` 288 | 289 | To send attachments, they need to be Base64 encoded 290 | 291 | ```ruby 292 | require 'base64' 293 | 294 | properties = { 295 | recipients: [{ address: { email: 'yourcustomer@theirdomain.com', name: 'Your Customer' }], 296 | content: 297 | { from: { name: 'Your Name', email: 'you@yourdomain.com' }, 298 | subject: 'I am a test email', 299 | html: '

Hi from {{sender}}This is a test

', 300 | attachments: [{ name: "attachment.txt", type: "text/plain", data: attachment }] 301 | } 302 | } 303 | 304 | # load your file contents first, then use Base64 to encode them 305 | encoded_attachment = Base64.encode64('My file contents') 306 | properties[:content][:attachments] = [{ name: "attachment.txt", type: "text/plain", data: encoded_attachment }] 307 | 308 | simple_spark.transmissions.create(properties) 309 | ``` 310 | 311 | see SparkPost API Documentation 312 | 313 | 314 | ### Subaccounts 315 | 316 | #### List 317 | 318 | List all Subaccounts 319 | 320 | ```ruby 321 | simple_spark.subaccounts.list 322 | ``` 323 | 324 | see SparkPost API Documentation 325 | 326 | #### Create 327 | 328 | Create a new Subaccount 329 | 330 | ```ruby 331 | properties = { 332 | name: 'Sparkle Ponies', key_label: 'API Key for Sparkle Ponies Subaccount', 333 | key_grants: ['smtp/inject', 'sending_domains/manage', 'message_events/view', 'suppression_lists/manage'] 334 | } 335 | simple_spark.subaccounts.create(properties) 336 | ``` 337 | 338 | see SparkPost API Documentation 339 | 340 | #### Retrieve 341 | 342 | Retrieves a Subaccount by its id 343 | 344 | ```ruby 345 | simple_spark.subaccounts.retrieve(123) 346 | ``` 347 | 348 | see SparkPost API Documentation 349 | 350 | #### Update 351 | 352 | Updates a Subaccount with new values 353 | 354 | ```ruby 355 | properties = { name: "new name" } 356 | simple_spark.subaccounts.update('mail.mydomain.com', properties) 357 | ``` 358 | 359 | see SparkPost API Documentation 360 | 361 | 362 | ### Messsage Events 363 | 364 | #### Samples 365 | 366 | List an example of the event data that will be included in a response from the Message Events search endpoint 367 | 368 | ```ruby 369 | simple_spark.message_events.samples 370 | ``` 371 | 372 | To limit to just some events 373 | 374 | ```ruby 375 | simple_spark.message_events.samples('bounce') 376 | ``` 377 | 378 | see SparkPost API Documentation 379 | 380 | #### Search 381 | 382 | Perform a filtered search for message event data. The response is sorted by descending timestamp. For full options you should consult the SparkPost API documentation 383 | 384 | ```ruby 385 | simple_spark.message_events.search(campaign_ids: 'christmas-campaign, summer-campaign') 386 | ``` 387 | 388 | see SparkPost API Documentation 389 | 390 | ### Webhooks 391 | 392 | #### List 393 | 394 | List all Webhooks, optionally providing a timezone property 395 | 396 | ```ruby 397 | simple_spark.webhooks.list('America/New_York') 398 | ``` 399 | 400 | see SparkPost API Documentation 401 | 402 | #### Create 403 | 404 | Create a new Webhook 405 | 406 | ```ruby 407 | simple_spark.webhooks.create(values) 408 | ``` 409 | 410 | see SparkPost API Documentation 411 | 412 | #### Retrieve 413 | 414 | Retrieves a Webhook 415 | 416 | ```ruby 417 | simple_spark.webhooks.retrieve(webhook_id) 418 | ``` 419 | 420 | see SparkPost API Documentation 421 | 422 | #### Update 423 | 424 | Updates a Webhook with new values 425 | 426 | ```ruby 427 | properties = { "name" => "New name" } 428 | simple_spark.webhooks.update(webhook_id, properties) 429 | ``` 430 | 431 | see SparkPost API Documentation 432 | 433 | #### Validate 434 | 435 | Validates a Webhook by sending an example message event batch from the Webhooks API to the target URL 436 | 437 | ```ruby 438 | simple_spark.webhooks.validate(webhook_id) 439 | ``` 440 | 441 | see SparkPost API Documentation 442 | 443 | #### Batch Status 444 | 445 | Retrieve the Batch Status Information for a Webhook 446 | 447 | ```ruby 448 | simple_spark.webhooks.batch_status(webhook_id) 449 | ``` 450 | 451 | see SparkPost API Documentation 452 | 453 | #### Samples 454 | 455 | List an example of the event data that will be sent from a webhook 456 | 457 | ```ruby 458 | simple_spark.webhooks.samples 459 | ``` 460 | 461 | To limit to just some events 462 | 463 | ```ruby 464 | simple_spark.webhooks.samples('bounce') 465 | ``` 466 | 467 | see SparkPost API Documentation 468 | 469 | ### Sending Domains 470 | 471 | #### List 472 | 473 | List all Sending Domains 474 | 475 | ```ruby 476 | simple_spark.sending_domains.list 477 | ``` 478 | 479 | see SparkPost API Documentation 480 | 481 | #### Create 482 | 483 | Create a new Sending Domain 484 | 485 | ```ruby 486 | simple_spark.sending_domains.create('mail.mydomain.com') 487 | ``` 488 | 489 | see SparkPost API Documentation 490 | 491 | #### Retrieve 492 | 493 | Retrieves a Sending Domain by its domain name 494 | 495 | ```ruby 496 | simple_spark.sending_domains.retrieve('mail.mydomain.com') 497 | ``` 498 | 499 | see SparkPost API Documentation 500 | 501 | #### Update 502 | 503 | Updates a Sending Domain with new values 504 | 505 | ```ruby 506 | properties = { "tracking_domain" => "new.tracking.domain" } 507 | simple_spark.sending_domains.update('mail.mydomain.com', properties) 508 | ``` 509 | 510 | see SparkPost API Documentation 511 | 512 | #### Verify 513 | 514 | Forces verification of a Sending Domain. 515 | 516 | Including the fields "dkim_verify" and/or "spf_verify" in the request initiates a check against the associated DNS record 517 | type for the specified sending domain.Including the fields "postmaster_at_verify" and/or "abuse_at_verify" in the request 518 | results in an email sent to the specified sending domain's postmaster@ and/or abuse@ mailbox where a verification link can 519 | be clicked. Including the fields "postmaster_at_token" and/or "abuse_at_token" in the request initiates a check of the provided 520 | token(s) against the stored token(s) for the specified sending domain. 521 | 522 | ```ruby 523 | properties = { "dkim_verify": true, "spf_verify": true } 524 | simple_spark.sending_domains.retrieve('mail.mydomain.com', properties) 525 | ``` 526 | 527 | see SparkPost API Documentation 528 | 529 | #### Delete 530 | 531 | Deletes a Sending Domain permanently 532 | 533 | ```ruby 534 | simple_spark.sending_domains.delete('mail.mydomain.com') 535 | ``` 536 | 537 | see SparkPost API Documentation 538 | 539 | ### Inbound Domains 540 | 541 | #### List 542 | 543 | List all Inbound Domains 544 | 545 | ```ruby 546 | simple_spark.inbound_domains.list 547 | ``` 548 | 549 | see SparkPost API Documentation 550 | 551 | #### Create 552 | 553 | Create a new Inbound Domain 554 | 555 | ```ruby 556 | simple_spark.inbound_domains.create('mail.mydomain.com') 557 | ``` 558 | 559 | see SparkPost API Documentation 560 | 561 | #### Retrieve 562 | 563 | Retrieves an Inbound Domain by its domain name 564 | 565 | ```ruby 566 | simple_spark.inbound_domains.retrieve('mail.mydomain.com') 567 | ``` 568 | 569 | see SparkPost API Documentation 570 | 571 | #### Delete 572 | 573 | Deletes an Inbound Domain permanently 574 | 575 | ```ruby 576 | simple_spark.inbound_domains.delete('mail.mydomain.com') 577 | ``` 578 | 579 | see SparkPost API Documentation 580 | 581 | ### Supression List 582 | 583 | #### Search 584 | 585 | Find supression list entries 586 | 587 | ```ruby 588 | params = { 589 | from: '2013-04-20T07:12', 590 | to: '2018-04-20T07:12' 591 | } 592 | simple_spark.suppression_list.create_or_update(params) 593 | ``` 594 | 595 | see SparkPost API Documentation 596 | 597 | #### Create or Update 598 | 599 | Bulk update supression list entries 600 | 601 | ```ruby 602 | recipients = { 603 | { 604 | recipient: "rcpt_1@example.com", 605 | transactional: true, 606 | description: "User requested to not receive any transactional emails." 607 | }, 608 | { 609 | recipient: "rcpt_2@example.com", 610 | non_transactional: true 611 | } 612 | } 613 | simple_spark.suppression_list.create_or_update(recipients) 614 | ``` 615 | 616 | see SparkPost API Documentation 617 | 618 | #### Retrieve 619 | 620 | ```ruby 621 | simple_spark.suppression_list.retrieve("rcpt_1@example.com") 622 | ``` 623 | 624 | see SparkPost API Documentation 625 | 626 | #### Delete 627 | 628 | ```ruby 629 | simple_spark.suppression_list.delete("rcpt_1@example.com") 630 | ``` 631 | 632 | see SparkPost API Documentation 633 | 634 | ### Relay Webhooks 635 | 636 | #### List 637 | 638 | List all Relay Webhooks 639 | 640 | ```ruby 641 | simple_spark.relay_webhooks.list 642 | ``` 643 | 644 | see SparkPost API Documentation 645 | 646 | #### Create 647 | 648 | Create a new Relay Webhook 649 | 650 | ```ruby 651 | properties = { 652 | name: "Replies Webhook", 653 | target: "https://webhooks.customer.example/replies", 654 | auth_token: "", 655 | match: { 656 | protocol: "SMTP", 657 | domain: "email.example.com" 658 | } 659 | } 660 | simple_spark.relay_webhooks.create(properties) 661 | ``` 662 | 663 | see SparkPost API Documentation 664 | 665 | #### Retrieve 666 | 667 | Retrieves a Relay Webhook by its id 668 | 669 | ```ruby 670 | simple_spark.relay_webhooks.retrieve(id) 671 | ``` 672 | 673 | see SparkPost API Documentation 674 | 675 | #### Update 676 | 677 | Updates a Relay Webhook with new values 678 | 679 | ```ruby 680 | properties = { name: "Replies Webhook" } 681 | simple_spark.relay_webhooks.update(id, properties) 682 | ``` 683 | 684 | see SparkPost API Documentation 685 | 686 | #### Delete 687 | 688 | Deletes a Relay Webhook permanently 689 | 690 | ```ruby 691 | simple_spark.relay_webhooks.delete(id) 692 | ``` 693 | 694 | see SparkPost API Documentation 695 | 696 | ### Templates 697 | 698 | #### List 699 | 700 | List all templates 701 | 702 | ```ruby 703 | simple_spark.templates.list 704 | ``` 705 | 706 | see SparkPost API Documentation 707 | 708 | #### Create 709 | 710 | Create a new Template 711 | 712 | ```ruby 713 | properties = { "name" => "Summer Sale!", 714 | "content"=> { "from" => "marketing@yourdomain.com", 715 | "subject"=> "Summer deals", 716 | "html"=> "Check out these deals!" 717 | } 718 | } 719 | simple_spark.templates.create(properties) 720 | ``` 721 | 722 | see SparkPost API Documentation 723 | 724 | #### Retrieve 725 | 726 | Retrieves a Template by its ID 727 | 728 | ```ruby 729 | draft = nil 730 | simple_spark.templates.retrieve(yourtemplateid, draft) 731 | ``` 732 | 733 | see SparkPost API Documentation 734 | 735 | #### Update 736 | 737 | Updates a Template with new values 738 | 739 | ```ruby 740 | properties = { "name" => "Sorry, the Winter Sale!" } 741 | update_published = false 742 | simple_spark.templates.update(yourtemplateid, properties, update_published) 743 | ``` 744 | 745 | see SparkPost API Documentation 746 | 747 | #### Preview 748 | 749 | Merges the template with the Substitution data and returns the result 750 | 751 | ```ruby 752 | properties = { substitution_data: { name: 'Mr test User' } } 753 | draft = nil 754 | simple_spark.templates.preview(yourtemplateid, properties, draft) 755 | ``` 756 | 757 | see SparkPost API Documentation 758 | 759 | #### Delete 760 | 761 | Deletes a template permanently 762 | 763 | ```ruby 764 | simple_spark.templates.delete(yourtemplateid) 765 | ``` 766 | 767 | see SparkPost API Documentation 768 | 769 | ## Changelog 770 | 771 | ### 1.0.4 772 | 773 | - Add Supression List Endpoint 774 | 775 | ### 1.0.3 776 | 777 | - Using JSON.generate instead of .to_json (https://github.com/leadmachineapp/simple_spark/pull/11) 778 | - Fixing inbound domains bug (https://github.com/leadmachineapp/simple_spark/pull/9) 779 | 780 | ### 1.0.2 781 | 782 | Add sparkpost error code into exception message to allow more specific error handling 783 | 784 | ### 1.0.1 785 | 786 | Suppress Excon warning for using :debug parameter 787 | 788 | ### 1.0.0 789 | 790 | As SparkPost have now stopped development on their own gem, and have recommended this one as being a better alternative, bumping version to 1.0.0 - the code has been running in production for a while now and seems stable and near feature complete. 791 | 792 | ### 0.0.13 793 | 794 | Adding status error code to message as SparkPost uses a wide range of status codes 795 | 796 | ### 0.0.12 797 | 798 | Check :progname before assigning 799 | 800 | ### 0.0.11 801 | 802 | - long day ... bug in 504 exception syntax came back with merge 803 | 804 | ### 0.0.10 805 | 806 | - Bug in 504 exception syntax 807 | 808 | ### 0.0.9 809 | 810 | - Breaking change: 204 responses now return an empty hash t simplify consuming code 811 | - Added logging, if debug is set then SimpleSpark will log its options and calls in addition to Excon. 812 | 813 | ### 0.0.8 814 | 815 | - Improved exception handling 816 | 817 | ### 0.0.7 818 | 819 | - Added Time Series to Metrics 820 | 821 | ### 0.0.6 822 | 823 | - Fixed accidental bug 824 | 825 | ### 0.0.5 826 | 827 | - Subaccounts endpoint added 828 | - Metrics main endpoints added 829 | 830 | ### 0.0.4 831 | 832 | - Merged pull request to fix Rails development check for debug 833 | 834 | ### 0.0.3 835 | 836 | - Breaking change: client paramaters are now a hash of options instead of ordered params 837 | - Added Subaccount support to client 838 | - Added Headers support to client 839 | 840 | ## Contributing 841 | 842 | Passing tests are encouraged going forwards, and generally code should follow most of the standard rules that Rubocop checks for. 843 | 844 | 1. Fork it ( https://github.com/leadmachineapp/simple_spark/fork ) 845 | 2. Create your feature branch (`git checkout -b my-new-feature`) 846 | 3. Commit your changes (`git commit -am 'Add some feature'`) 847 | 4. Push to the branch (`git push origin my-new-feature`) 848 | 5. Create a new Pull Request 849 | --------------------------------------------------------------------------------