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.
@@ -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
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+
5
+ module ChainMail
6
+ class Railtie < Rails::Railtie
7
+ initializer "chain_mail.add_delivery_method" do
8
+ ActionMailer::Base.add_delivery_method :chain_mail, ChainMail::Delivery
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChainMail
4
+ VERSION = "0.1.0"
5
+ 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
@@ -0,0 +1,4 @@
1
+ module ChainMail
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end