mailpace-rails 0.4.3 → 0.5.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 +4 -4
- data/README.md +3 -1
- data/lib/mailpace-rails/engine.rb +3 -1
- data/lib/mailpace-rails/response.rb +103 -0
- data/lib/mailpace-rails/version.rb +1 -1
- data/lib/mailpace-rails.rb +38 -33
- metadata +4 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c31f68a3d8b609aae9c7b86a5012a3c681f8309e4e8a4e71c1c79149efd4cb7e
|
|
4
|
+
data.tar.gz: 4df6d4972fc3b231dd7db9093b249759a55279e254499cfa8a2e7224905c2497
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c1711d716265352e54655562c3ecc0c53972c30e5123e648cc1cba7a63be36c0358fbfe922aecb179944e33cbac5ac2a29e0c47e3870909dfad96ca927eb979
|
|
7
|
+
data.tar.gz: 3f897e1309b778bcf0356a86df2baeb1bb52395c53749698d63004fdd94168c7238ed1519806577e35283e877bf1f3a63963060e61582239a26eda18c0f2ba6c
|
data/README.md
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
[](https://badge.fury.io/rb/mailpace-rails)
|
|
5
|
-
[](https://github.com/mailpace/mailpace-rails/actions/workflows/ci.yml)
|
|
6
6
|
|
|
7
7
|
[MailPace](https://mailpace.com) lets you send transactional emails from your app over an easy to use API.
|
|
8
8
|
|
|
9
9
|
The MailPace Rails Gem is a plug in for ActionMailer to send emails via [MailPace](https://mailpace.com) to make sending emails from Rails apps super simple.
|
|
10
10
|
|
|
11
|
+
> **New in 0.5.0: The `httparty` dependency has been removed — requests now use Ruby's built-in `Net::HTTP`, and the delivery response stays backward compatible**
|
|
12
|
+
|
|
11
13
|
> **New in 0.4.0: [Idempotent Requests](https://docs.mailpace.com/guide/idempotency/), Improved Error Handling, InReplyTo and References support**
|
|
12
14
|
|
|
13
15
|
> **New in 0.3.0: The ability to consume [inbound emails](https://docs.mailpace.com/guide/inbound/) from MailPace via ActionMailbox**
|
|
@@ -4,7 +4,9 @@ module Mailpace
|
|
|
4
4
|
# Provides the delivery method & sets up action mailbox
|
|
5
5
|
class Engine < ::Rails::Engine
|
|
6
6
|
initializer 'mailpace.add_delivery_method', before: 'action_mailer.set_configs' do
|
|
7
|
-
|
|
7
|
+
ActiveSupport.on_load(:action_mailer) do
|
|
8
|
+
add_delivery_method(:mailpace, Mailpace::DeliveryMethod)
|
|
9
|
+
end
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
config.action_mailbox.mailpace = ActiveSupport::OrderedOptions.new
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'delegate'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'net/http'
|
|
6
|
+
|
|
7
|
+
module Mailpace
|
|
8
|
+
# The value returned by Mailpace::DeliveryMethod#deliver!.
|
|
9
|
+
#
|
|
10
|
+
# Because the delivery method sets `return_response: true`, Mail hands this
|
|
11
|
+
# object back from `mail.deliver!` / `deliver_now!`. It mirrors the public
|
|
12
|
+
# interface of the HTTParty::Response this gem used to return, so that
|
|
13
|
+
# removing the httparty dependency does not change what callers can do with
|
|
14
|
+
# the result: `res['id']`, `res.parsed_response`, `res.code`, `res.body`,
|
|
15
|
+
# `res.headers` and the `*?` status helpers all keep working.
|
|
16
|
+
#
|
|
17
|
+
# Not carried over from HTTParty::Response: `#request` (an HTTParty::Request)
|
|
18
|
+
# and Marshal support (`_dump` / `_load`).
|
|
19
|
+
class Response
|
|
20
|
+
# Presents the parsed headers the way HTTParty did: case-insensitive lookup
|
|
21
|
+
# with joined values (`headers['Content-Type']` => "application/json").
|
|
22
|
+
class Headers < ::SimpleDelegator
|
|
23
|
+
include ::Net::HTTPHeader
|
|
24
|
+
|
|
25
|
+
def initialize(values = {})
|
|
26
|
+
@header = {}
|
|
27
|
+
values.each_pair do |key, value|
|
|
28
|
+
Array(value).each { |sub_value| add_field(key, sub_value) }
|
|
29
|
+
end
|
|
30
|
+
super(@header)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
attr_reader :response, :body, :headers
|
|
35
|
+
|
|
36
|
+
def initialize(response)
|
|
37
|
+
@response = response
|
|
38
|
+
@body = response.body
|
|
39
|
+
@headers = Headers.new(response.to_hash)
|
|
40
|
+
@parsed_response = parse(@body)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def parsed_response
|
|
44
|
+
@parsed_response
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def code
|
|
48
|
+
response.code.to_i
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def http_version
|
|
52
|
+
response.http_version
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def nil?
|
|
56
|
+
response.nil? || body.nil? || body.empty?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_s
|
|
60
|
+
body.to_s
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def to_hash
|
|
64
|
+
parsed_response
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def [](key)
|
|
68
|
+
parsed_response[key] if parsed_response.respond_to?(:[])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def inspect
|
|
72
|
+
"#<#{self.class} code=#{code} parsed_response=#{parsed_response.inspect}>"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def method_missing(name, *args, &block)
|
|
76
|
+
return parsed_response.send(name, *args, &block) if parsed_response.respond_to?(name)
|
|
77
|
+
|
|
78
|
+
super
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def respond_to_missing?(name, include_private = false)
|
|
82
|
+
parsed_response.respond_to?(name, include_private) || super
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# HTTParty defines a predicate per HTTP status class (ok?, created?,
|
|
86
|
+
# not_found?, server_error?, ...). Rebuild the same set from Net::HTTP's
|
|
87
|
+
# tables so status checks keep working.
|
|
88
|
+
::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge(::Net::HTTPResponse::CODE_TO_OBJ).each do |_code, klass|
|
|
89
|
+
name = klass.name.sub('Net::HTTP', '')
|
|
90
|
+
name = "#{name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase}?"
|
|
91
|
+
|
|
92
|
+
define_method(name) { klass === response }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def parse(body)
|
|
98
|
+
JSON.parse(body.to_s)
|
|
99
|
+
rescue JSON::ParserError
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
data/lib/mailpace-rails.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
require 'action_mailer'
|
|
2
2
|
require 'action_mailbox/engine'
|
|
3
|
-
require '
|
|
3
|
+
require 'net/http'
|
|
4
4
|
require 'uri'
|
|
5
5
|
require 'json'
|
|
6
6
|
require 'mailpace-rails/version'
|
|
7
|
+
require 'mailpace-rails/response'
|
|
7
8
|
require 'mailpace-rails/engine' if defined? Rails
|
|
8
9
|
|
|
9
10
|
module Mailpace
|
|
@@ -27,32 +28,33 @@ module Mailpace
|
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
check_delivery_params(mail)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
31
|
+
|
|
32
|
+
uri = URI('https://app.mailpace.com/api/v1/send')
|
|
33
|
+
request = Net::HTTP::Post.new(uri)
|
|
34
|
+
request['User-Agent'] = "MailPace Rails Gem v#{Mailpace::Rails::VERSION}"
|
|
35
|
+
request['Accept'] = 'application/json'
|
|
36
|
+
request['Content-Type'] = 'application/json'
|
|
37
|
+
request['Mailpace-Server-Token'] = settings[:api_token]
|
|
38
|
+
request['Idempotency-Key'] = mail.header['idempotency_key'].to_s if mail.header['idempotency_key']
|
|
39
|
+
request.body = {
|
|
40
|
+
from: address_list(mail.header[:from])&.addresses&.first.to_s,
|
|
41
|
+
to: address_list(mail.header[:to])&.addresses&.join(','),
|
|
42
|
+
subject: mail.subject,
|
|
43
|
+
htmlbody: htmlbody,
|
|
44
|
+
textbody: textbody,
|
|
45
|
+
cc: address_list(mail.header[:cc])&.addresses&.join(','),
|
|
46
|
+
bcc: address_list(mail.header[:bcc])&.addresses&.join(','),
|
|
47
|
+
replyto: address_list(mail.header[:reply_to])&.addresses&.join(','),
|
|
48
|
+
inreplyto: mail.header['In-Reply-To'].to_s,
|
|
49
|
+
references: mail.header['References'].to_s,
|
|
50
|
+
list_unsubscribe: mail.header['list_unsubscribe'].to_s,
|
|
51
|
+
attachments: format_attachments(mail.attachments),
|
|
52
|
+
tags: mail.header['tags'].to_s
|
|
53
|
+
}.delete_if { |_key, value| value.blank? }.to_json
|
|
54
|
+
|
|
55
|
+
result = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
|
56
|
+
http.request(request)
|
|
57
|
+
end
|
|
56
58
|
|
|
57
59
|
handle_response(result)
|
|
58
60
|
end
|
|
@@ -72,12 +74,13 @@ module Mailpace
|
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
def handle_response(result)
|
|
75
|
-
|
|
77
|
+
response = Mailpace::Response.new(result)
|
|
78
|
+
return response if result.is_a?(Net::HTTPOK)
|
|
76
79
|
|
|
77
|
-
|
|
78
|
-
error_message =
|
|
80
|
+
error_message = join_error_messages(response.parsed_response)
|
|
81
|
+
error_message = "HTTP #{response.code}" if error_message.empty?
|
|
79
82
|
|
|
80
|
-
raise DeliveryError, "MAILPACE Error: #{error_message}"
|
|
83
|
+
raise DeliveryError, "MAILPACE Error: #{error_message}"
|
|
81
84
|
end
|
|
82
85
|
|
|
83
86
|
def format_attachments(attachments)
|
|
@@ -101,9 +104,11 @@ module Mailpace
|
|
|
101
104
|
end
|
|
102
105
|
end
|
|
103
106
|
|
|
104
|
-
def join_error_messages(
|
|
107
|
+
def join_error_messages(parsed_response)
|
|
105
108
|
# Join 'error' and 'errors' keys from response into a single string
|
|
106
|
-
|
|
109
|
+
return '' unless parsed_response.is_a?(Hash)
|
|
110
|
+
|
|
111
|
+
[parsed_response['error'], parsed_response['errors']].compact.join(', ')
|
|
107
112
|
end
|
|
108
113
|
end
|
|
109
114
|
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailpace-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- MailPace
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: actionmailer
|
|
@@ -52,20 +51,6 @@ dependencies:
|
|
|
52
51
|
- - ">="
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
53
|
version: 6.0.0
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: httparty
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.18.1
|
|
62
|
-
type: :runtime
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - ">="
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: 0.18.1
|
|
69
54
|
- !ruby/object:Gem::Dependency
|
|
70
55
|
name: rails
|
|
71
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -109,6 +94,7 @@ files:
|
|
|
109
94
|
- config/routes.rb
|
|
110
95
|
- lib/mailpace-rails.rb
|
|
111
96
|
- lib/mailpace-rails/engine.rb
|
|
97
|
+
- lib/mailpace-rails/response.rb
|
|
112
98
|
- lib/mailpace-rails/version.rb
|
|
113
99
|
homepage: https://mailpace.com
|
|
114
100
|
licenses:
|
|
@@ -116,7 +102,6 @@ licenses:
|
|
|
116
102
|
metadata:
|
|
117
103
|
source_code_uri: https://github.com/mailpace/mailpace-rails
|
|
118
104
|
changelog_uri: https://github.com/mailpace/mailpace-rails/blob/master/CHANGELOG.md
|
|
119
|
-
post_install_message:
|
|
120
105
|
rdoc_options: []
|
|
121
106
|
require_paths:
|
|
122
107
|
- lib
|
|
@@ -131,8 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
131
116
|
- !ruby/object:Gem::Version
|
|
132
117
|
version: '0'
|
|
133
118
|
requirements: []
|
|
134
|
-
rubygems_version:
|
|
135
|
-
signing_key:
|
|
119
|
+
rubygems_version: 4.0.20
|
|
136
120
|
specification_version: 4
|
|
137
121
|
summary: Lets you send transactional emails from your app over an easy to use API
|
|
138
122
|
test_files: []
|