paubox 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6b17ee76a0b045040db36865f166c659df8b29ba
4
+ data.tar.gz: 8618b773e3b75644e4480b815c66d3613e6a8ef1
5
+ SHA512:
6
+ metadata.gz: 4eaa0bc9cb2d23b0aa7f36e1f2a1a30bcfaf798a4914857f273160b8c4bd60ea351145ae226fe5d2cf7c913c93b22574ef0f4d4770a50d4043ad1a843939f89c
7
+ data.tar.gz: d53e5917f0d7dbbefcad209a3b3a6bdc39b08bd0c1a5b8ffff85a5281772facb465df31d135baa88a2084b5eabcd10005b94c83eea96838609d33c5325b4629e
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.14.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in paubox_ruby.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2018 Paubox Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Paubox Gem
2
+ This is the official Ruby wrapper for the Paubox Transactional Email HTTP API. The Paubox Transactional Email API allows your application to send secure, HIPAA-compliant email and track deliveries and opens. This gem is currently in pre-alpha development.
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```ruby
9
+ gem 'paubox'
10
+ ```
11
+
12
+ And then execute:
13
+
14
+ $ bundle install
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install paubox
19
+
20
+ ## Contributing
21
+
22
+ Bug reports and pull requests are welcome on GitHub at https://github.com/paubox/paubox_ruby.
23
+
24
+
25
+ ## License
26
+
27
+ Copyright © 2018 Paubox, Inc. See LICENSE for details.
28
+
data/Rakefile ADDED
@@ -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
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "paubox_ruby"
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(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,19 @@
1
+ module Mail
2
+ class Paubox
3
+ attr_accessor :settings
4
+
5
+ def initialize(settings)
6
+ @settings = settings
7
+ end
8
+
9
+ def deliver!(mail)
10
+ client = ::Paubox::Client.new(settings)
11
+ response = client.send_mail(mail)
12
+ puts response
13
+ end
14
+ end
15
+
16
+ class Message
17
+ attr_accessor :source_tracking_id, :status
18
+ end
19
+ end
data/lib/paubox.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'paubox/version'
2
+ require 'paubox/client'
3
+ require 'paubox/format_helper'
4
+ require 'paubox/mail_to_message'
5
+ require 'paubox/message'
6
+ require 'mail/paubox'
7
+
8
+ module Paubox
9
+ class << self
10
+ attr_accessor :configuration
11
+ end
12
+
13
+ def self.configure
14
+ self.configuration ||= Configuration.new
15
+ yield(configuration)
16
+ end
17
+
18
+ class Configuration
19
+ attr_accessor :api_key, :api_user
20
+ end
21
+ end
@@ -0,0 +1,73 @@
1
+ module Paubox
2
+ # Client sends API requests to Paubox API
3
+ class Client
4
+ require 'rest-client'
5
+ attr_reader :api_key, :api_user, :api_host, :api_protocol, :api_version
6
+
7
+ def initialize(args = {})
8
+ args = defaults.merge(args)
9
+ @api_key = args[:api_key]
10
+ @api_user = args[:api_user]
11
+ @api_host = args[:api_host]
12
+ @api_protocol = args[:api_protocol]
13
+ @api_version = args[:api_version]
14
+ @test_mode = args[:test_mode]
15
+ @api_base_endpoint = api_base_endpoint
16
+ @allow_non_tls = args.fetch(:allow_non_tls, false)
17
+ end
18
+
19
+ def api_status
20
+ url = request_endpoint('status')
21
+ RestClient.get(url, accept: :json)
22
+ end
23
+
24
+ def send_mail(mail)
25
+ case mail
26
+ when Mail::Message
27
+ payload = MailToMessage.new(mail, { allow_non_tls: @allow_non_tls })
28
+ .send_message_payload
29
+ when Hash
30
+ payload = Message.new(mail).send_message_payload
31
+ end
32
+ url = request_endpoint('messages')
33
+ response = RestClient.post(url, payload, auth_header)
34
+ if mail.class == Mail::Message
35
+ mail.source_tracking_id = JSON.parse(response.body)['sourceTrackingId']
36
+ end
37
+ JSON.parse(response.body)
38
+ end
39
+ alias deliver_mail send_mail
40
+
41
+ def email_disposition(source_tracking_id)
42
+ url = "#{request_endpoint('message_receipt')}?sourceTrackingId=#{source_tracking_id}"
43
+ response = RestClient.get(url, auth_header)
44
+ JSON.parse(response.body)
45
+ end
46
+ alias message_receipt email_disposition
47
+
48
+ private
49
+
50
+ def auth_header
51
+ { accept: :json,
52
+ content_type: :json,
53
+ :Authorization => "Token token=#{@api_key}" }
54
+ end
55
+
56
+ def api_base_endpoint
57
+ "#{api_protocol}#{api_host}/#{api_version}/#{api_user}"
58
+ end
59
+
60
+ def request_endpoint(endpoint)
61
+ "#{api_base_endpoint}/#{endpoint}"
62
+ end
63
+
64
+ def defaults
65
+ { api_key: Paubox.configuration.api_key,
66
+ api_user: Paubox.configuration.api_user,
67
+ api_host: 'api.paubox.net',
68
+ api_protocol: 'https://',
69
+ api_version: 'v1',
70
+ test_mode: false }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,55 @@
1
+ module Paubox
2
+ # Utility methods for Message and MailToMessage
3
+ module FormatHelper
4
+ require 'base64'
5
+ BASE64_REGEX = %r(/^(?:[A-Za-z0-9+\/]{4}\n?)*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/)
6
+
7
+ def base64_encoded?(value)
8
+ return false unless value.is_a?(String)
9
+ !value.strip.match(BASE64_REGEX).nil?
10
+ end
11
+
12
+ def base64_encode_if_needed(str)
13
+ return str if base64_encoded?(str.to_s)
14
+ Base64.encode64(str.to_s)
15
+ end
16
+
17
+ # Converts hash keys to strings and maps them to expected JSON key.
18
+ # Also converts hashes in shallow arrays.
19
+ def convert_keys_to_json_version(hash)
20
+ converted = {}
21
+ hash.each_pair do |key, val|
22
+ converted[ruby_to_json_key(key)] = val.is_a?(Hash) ? convert_keys_to_json_version(val) : val
23
+ next unless val.is_a?(Array)
24
+ val.each_with_index { |el, i| val[i] = convert_keys_to_json_version(el) if el.is_a?(Hash) }
25
+ end
26
+ converted
27
+ end
28
+
29
+ def ruby_to_json_key(key)
30
+ { reply_to: 'reply-to', html_content: 'text/html', text_content: 'text/plain',
31
+ filename: 'fileName', file_name: 'fileName', content_type: 'contentType',
32
+ allow_non_tls: 'allowNonTLS' }[key] || key.to_s
33
+ end
34
+
35
+ # def get_values_whitelist(*vals)
36
+ # vals.map { |k| next unless mail[k]; [ruby_to_json_key(k), mail[k]] }.to_h
37
+ # end
38
+
39
+ def string_or_array_to_array(object)
40
+ case object
41
+ when String
42
+ a = object.split(',').map { |str| squish(str) }
43
+ when Array
44
+ a = object.map { |s| squish(s) }
45
+ else
46
+ return []
47
+ end
48
+ a.reject(&:empty?)
49
+ end
50
+
51
+ def squish(str)
52
+ str.to_s.split.join(' ')
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,68 @@
1
+ module Paubox
2
+ # The MailToMessage class takes a Ruby Mail object and attempts to parse it
3
+ # into a Hash formatted for the JSON payload of HTTP api request.
4
+ class MailToMessage
5
+ include Paubox::FormatHelper
6
+ attr_reader :mail
7
+ require 'tempfile'
8
+
9
+ def initialize(mail, args = {})
10
+ @mail = mail
11
+ @allow_non_tls = args.fetch(:allow_non_tls, false)
12
+ end
13
+
14
+ def send_message_payload
15
+ { data: { message: convert_keys_to_json_version(build_parts) } }.to_json
16
+ end
17
+
18
+ private
19
+
20
+ def build_attachments
21
+ attachments = mail.attachments
22
+ return [] if attachments.empty?
23
+ packaged_attachments = []
24
+ attachments.each do |attch|
25
+ packaged_attachments << { content: convert_binary_to_base64(attch.body.decoded),
26
+ file_name: attch.filename,
27
+ content_type: attch.mime_type }
28
+ end
29
+ packaged_attachments
30
+ end
31
+
32
+ def build_content
33
+ content = {}
34
+ if mail.multipart?
35
+ html_content = mail.html_part.body.to_s if mail.html_part
36
+ text_content = mail.text_part.body.to_s if mail.text_part
37
+ content[:html_content] = html_content unless html_content.empty?
38
+ content[:text_content] = text_content unless text_content.empty?
39
+ else
40
+ content[:text_content] = mail.body.to_s
41
+ end
42
+ content
43
+ end
44
+
45
+ def build_headers
46
+ %i[from reply_to subject].map { |k| [k, mail[k].to_s] }.to_h
47
+ end
48
+
49
+ def build_parts
50
+ msg = {}
51
+ msg[:recipients] = string_or_array_to_array(mail.to)
52
+ msg[:recipients] += string_or_array_to_array(mail.cc)
53
+ msg[:bcc] = string_or_array_to_array(mail.bcc)
54
+ msg[:allow_non_tls] = @allow_non_tls
55
+ msg[:headers] = build_headers
56
+ msg[:content] = build_content
57
+ msg[:attachments] = build_attachments
58
+ msg
59
+ end
60
+
61
+ def convert_binary_to_base64(f)
62
+ file = Tempfile.new(encoding: 'ascii-8bit')
63
+ file.write(f)
64
+ file.rewind
65
+ Base64.encode64(file.read)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,73 @@
1
+ module Paubox
2
+ # The Message class is for building a Paubox email message using a hash.
3
+ class Message
4
+ include Paubox::FormatHelper
5
+ attr_accessor :from, :to, :cc, :bcc, :subject, :reply_to, :text_content,
6
+ :html_content, :allow_non_tls
7
+
8
+ def initialize(args)
9
+ @from = args[:from]
10
+ @to = args[:to]
11
+ @cc = args[:cc]
12
+ @bcc = args[:bcc]
13
+ @subject = args[:subject]
14
+ @reply_to = args[:reply_to]
15
+ @text_content = args[:text_content]
16
+ @html_content = args[:html_content]
17
+ @packaged_attachments = []
18
+ @attachments = build_attachments(args[:attachments])
19
+ @allow_non_tls = args.fetch(:allow_non_tls, false)
20
+ end
21
+
22
+ def send_message_payload
23
+ { data: { message: convert_keys_to_json_version(build_parts) } }.to_json
24
+ end
25
+
26
+ def add_attachment(file_path)
27
+ @packaged_attachments << { filename: file_path.split('/').last,
28
+ content_type: `file --b --mime-type #{file_path}`.chomp,
29
+ content: Base64.encode64(File.read(file_path)) }
30
+ end
31
+
32
+ def attachments
33
+ @packaged_attachments
34
+ end
35
+
36
+ def attachments=(args)
37
+ @attachments = build_attachments(args)
38
+ end
39
+
40
+ private
41
+
42
+ def build_attachments(args)
43
+ return (@packaged_attachments = []) if args.to_a.empty?
44
+ args.each do |a|
45
+ a[:content] = base64_encode_if_needed(a[:content])
46
+ @packaged_attachments << a
47
+ end
48
+ @packaged_attachments
49
+ end
50
+
51
+ def build_content
52
+ content = {}
53
+ content[:text_content] = text_content if text_content
54
+ content[:html_content] = html_content if html_content
55
+ content
56
+ end
57
+
58
+ def build_headers
59
+ %i[from reply_to subject].map { |k| [k, self.send(k)] }.to_h
60
+ end
61
+
62
+ def build_parts
63
+ msg = {}
64
+ msg[:recipients] = string_or_array_to_array(to) + string_or_array_to_array(cc)
65
+ msg[:allow_non_tls] = @allow_non_tls
66
+ msg[:bcc] = string_or_array_to_array(bcc)
67
+ msg[:headers] = build_headers
68
+ msg[:content] = build_content
69
+ msg[:attachments] = attachments
70
+ msg
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module Paubox
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1 @@
1
+ require 'paubox'
@@ -0,0 +1,32 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'paubox/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'paubox'
8
+ spec.version = Paubox::VERSION
9
+ spec.authors = ['Paubox', 'Jonathan Greeley']
10
+ spec.email = ['jon.r.greeley@gmail.com']
11
+
12
+ spec.summary = "Paubox's Official Ruby SDK"
13
+ spec.description = "Ruby SDK for interacting with the Paubox Transactional Email HTTP API."
14
+ spec.homepage = 'https://www.paubox.com'
15
+ spec.license = 'Apache-2.0'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.14'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.2'
27
+ spec.add_development_dependency 'webmock', '~> 2.1'
28
+ spec.add_development_dependency 'pry'
29
+
30
+ spec.add_dependency 'mail', '~> 2.6', '>= 2.6.4'
31
+ spec.add_dependency 'rest-client', '~> 2.0', '>= 2.0.2'
32
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paubox
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Paubox
8
+ - Jonathan Greeley
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2018-04-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.14'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.14'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.2'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.2'
56
+ - !ruby/object:Gem::Dependency
57
+ name: webmock
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '2.1'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '2.1'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: mail
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '2.6'
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 2.6.4
94
+ type: :runtime
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '2.6'
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.6.4
104
+ - !ruby/object:Gem::Dependency
105
+ name: rest-client
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.0'
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 2.0.2
114
+ type: :runtime
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '2.0'
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 2.0.2
124
+ description: Ruby SDK for interacting with the Paubox Transactional Email HTTP API.
125
+ email:
126
+ - jon.r.greeley@gmail.com
127
+ executables: []
128
+ extensions: []
129
+ extra_rdoc_files: []
130
+ files:
131
+ - ".gitignore"
132
+ - ".rspec"
133
+ - ".travis.yml"
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - bin/console
139
+ - bin/setup
140
+ - lib/mail/paubox.rb
141
+ - lib/paubox.rb
142
+ - lib/paubox/client.rb
143
+ - lib/paubox/format_helper.rb
144
+ - lib/paubox/mail_to_message.rb
145
+ - lib/paubox/message.rb
146
+ - lib/paubox/version.rb
147
+ - lib/paubox_ruby.rb
148
+ - paubox_ruby.gemspec
149
+ homepage: https://www.paubox.com
150
+ licenses:
151
+ - Apache-2.0
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 2.6.13
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: Paubox's Official Ruby SDK
173
+ test_files: []