chain_mail 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 +7 -0
- data/.pre-commit-config.yaml +9 -0
- data/.rspec +3 -0
- data/.rubocop.yml +24 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +21 -0
- data/README.md +220 -0
- data/Rakefile +12 -0
- data/assets/images/logo.png +0 -0
- data/chain_mail.gemspec +38 -0
- data/config/initializers/chain_mail.rb +16 -0
- data/lib/chain_mail/configuration.rb +23 -0
- data/lib/chain_mail/delivery.rb +107 -0
- data/lib/chain_mail/providers/base.rb +28 -0
- data/lib/chain_mail/providers/brevo.rb +23 -0
- data/lib/chain_mail/providers/mailgun.rb +55 -0
- data/lib/chain_mail/providers/one_signal.rb +21 -0
- data/lib/chain_mail/providers/postmark.rb +21 -0
- data/lib/chain_mail/providers/send_grid.rb +29 -0
- data/lib/chain_mail/providers/send_pulse.rb +90 -0
- data/lib/chain_mail/providers/ses.rb +25 -0
- data/lib/chain_mail/railtie.rb +11 -0
- data/lib/chain_mail/version.rb +5 -0
- data/lib/chain_mail.rb +58 -0
- data/sig/chain_mail.rbs +4 -0
- data/vendor/sendpulse/sendpulse_api.rb +656 -0
- metadata +102 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "json"
|
5
|
+
require "base64"
|
6
|
+
require_relative "../../../vendor/sendpulse/sendpulse_api"
|
7
|
+
|
8
|
+
module ChainMail
|
9
|
+
module Providers
|
10
|
+
class SendPulse < Base
|
11
|
+
def self.validate_credentials(creds)
|
12
|
+
user_id = creds[:client_id]
|
13
|
+
secret = creds[:client_secret]
|
14
|
+
|
15
|
+
if user_id.nil? || user_id.to_s.strip.empty? ||
|
16
|
+
secret.nil? || secret.to_s.strip.empty?
|
17
|
+
{
|
18
|
+
success: false,
|
19
|
+
response: nil,
|
20
|
+
error: "Missing SendPulse credentials: client_id and client_secret are required"
|
21
|
+
}
|
22
|
+
else
|
23
|
+
{ success: true }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.initialize_api(user_id, secret)
|
28
|
+
api = SendpulseApi.new(user_id, secret)
|
29
|
+
{ success: true, api: api }
|
30
|
+
rescue StandardError => e
|
31
|
+
{
|
32
|
+
success: false,
|
33
|
+
response: nil,
|
34
|
+
error: "Failed to initialize SendPulse API: #{e.message}"
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.generate_plain_text(mail)
|
39
|
+
mail.text_part&.decoded || mail.body.decoded.gsub(/<[^>]*>/, "")
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.build_email_payload(mail)
|
43
|
+
{
|
44
|
+
email: {
|
45
|
+
from: { name: "ChainMail", email: mail.from.first },
|
46
|
+
to: mail.to.map { |email| { name: "", email: email } },
|
47
|
+
subject: mail.subject,
|
48
|
+
htmlbody: mail.body.decoded,
|
49
|
+
textbody: generate_plain_text(mail),
|
50
|
+
attachments: []
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.handle_api_result(result)
|
56
|
+
if result[:is_error]
|
57
|
+
{ success: false, response: nil, error: result[:message] || "SendPulse API error" }
|
58
|
+
else
|
59
|
+
{ success: true, response: result[:data], error: nil }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.deliver(mail, creds)
|
64
|
+
# Validate credentials
|
65
|
+
validation_result = validate_credentials(creds)
|
66
|
+
return validation_result unless validation_result[:success]
|
67
|
+
|
68
|
+
# Initialize API
|
69
|
+
user_id = creds[:client_id]
|
70
|
+
secret = creds[:client_secret]
|
71
|
+
api_result = initialize_api(user_id, secret)
|
72
|
+
return api_result unless api_result[:success]
|
73
|
+
|
74
|
+
# Build email payload and send
|
75
|
+
email_payload = build_email_payload(mail)
|
76
|
+
begin
|
77
|
+
result = api_result[:api].smtp_send_mail(email_payload[:email])
|
78
|
+
# Handle API result
|
79
|
+
handle_api_result(result)
|
80
|
+
rescue StandardError => e
|
81
|
+
{
|
82
|
+
success: false,
|
83
|
+
response: nil,
|
84
|
+
error: e.message
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "aws-sdk-ses"
|
4
|
+
|
5
|
+
module ChainMail
|
6
|
+
module Providers
|
7
|
+
class SES < Base
|
8
|
+
def self.deliver(mail, creds)
|
9
|
+
client = Aws::SES::Client.new(
|
10
|
+
region: creds[:region],
|
11
|
+
access_key_id: creds[:access_key_id],
|
12
|
+
secret_access_key: creds[:secret_access_key]
|
13
|
+
)
|
14
|
+
client.send_email({
|
15
|
+
destination: { to_addresses: mail.to },
|
16
|
+
message: {
|
17
|
+
body: { html: { charset: "UTF-8", data: mail.body.decoded } },
|
18
|
+
subject: { charset: "UTF-8", data: mail.subject }
|
19
|
+
},
|
20
|
+
source: mail.from.first
|
21
|
+
})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/chain_mail.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "chain_mail/version"
|
4
|
+
require "chain_mail/configuration"
|
5
|
+
require "chain_mail/railtie" if defined?(Rails::Railtie)
|
6
|
+
|
7
|
+
module ChainMail
|
8
|
+
autoload :Delivery, "chain_mail/delivery"
|
9
|
+
|
10
|
+
module Providers
|
11
|
+
autoload :Base, "chain_mail/providers/base"
|
12
|
+
autoload :Brevo, "chain_mail/providers/brevo"
|
13
|
+
autoload :SendGrid, "chain_mail/providers/send_grid"
|
14
|
+
autoload :Postmark, "chain_mail/providers/postmark"
|
15
|
+
autoload :SES, "chain_mail/providers/ses"
|
16
|
+
autoload :Mailgun, "chain_mail/providers/mailgun"
|
17
|
+
autoload :SendPulse, "chain_mail/providers/send_pulse"
|
18
|
+
autoload :OneSignal, "chain_mail/providers/one_signal"
|
19
|
+
end
|
20
|
+
|
21
|
+
class Error < StandardError; end
|
22
|
+
|
23
|
+
# Provider registry for dynamic adapter management
|
24
|
+
@provider_registry = {
|
25
|
+
brevo: Providers::Brevo,
|
26
|
+
send_grid: Providers::SendGrid,
|
27
|
+
postmark: Providers::Postmark,
|
28
|
+
ses: Providers::SES,
|
29
|
+
mailgun: Providers::Mailgun,
|
30
|
+
send_pulse: Providers::SendPulse,
|
31
|
+
one_signal: Providers::OneSignal
|
32
|
+
}
|
33
|
+
|
34
|
+
def self.provider_registry
|
35
|
+
@provider_registry
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.register_provider(symbol, klass)
|
39
|
+
@provider_registry[symbol.to_sym] = klass
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.unregister_provider(symbol)
|
43
|
+
@provider_registry.delete(symbol.to_sym)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Configuration entrypoint
|
47
|
+
def self.configure
|
48
|
+
yield(configuration)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.configuration
|
52
|
+
@configuration ||= Configuration.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.config
|
56
|
+
configuration
|
57
|
+
end
|
58
|
+
end
|
data/sig/chain_mail.rbs
ADDED