keplars 1.0.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
+ SHA256:
3
+ metadata.gz: 68ef4b129e532343682259d772000266f0ee10b38d22a6520f1991922652ab84
4
+ data.tar.gz: 2e18e8eb8fe9a28f9e751251db6ff64e29c6f067e7c55e3ba44d7e5d740b8936
5
+ SHA512:
6
+ metadata.gz: 749cd3e2041498a1b263d2908959d67b65c7b45c09afeaf7f369bf18d546dfc3add1b034b87f19c4201b2c4f3a6d38da1d1bd372bac16c1f3e5a6bb8130ef64b
7
+ data.tar.gz: b6e1ae77b8959db16134f74e5b146051bfff8536f028e7a063de01f79276702592fbe8294707fb38d36327ad2907891d49f4c243d288f5b7d0ae5050d8beecad
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # Keplars Email SDK for Ruby
2
+
3
+ Official Ruby SDK for the Keplars Email API - modern transactional email service with priority-based delivery.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'keplars'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ gem install keplars
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```ruby
28
+ require 'keplars'
29
+
30
+ client = Keplars::Client.new(api_key: 'kms_<workspaceId>.live_<secret>')
31
+
32
+ result = client.emails.send_instant(
33
+ from: 'noreply@yourdomain.com',
34
+ to: 'user@example.com',
35
+ subject: 'Your verification code is 123456',
36
+ html: '<p>Your verification code is <strong>123456</strong></p>'
37
+ )
38
+
39
+ puts result[:data][:job_id]
40
+ ```
41
+
42
+ ### API Key Types
43
+
44
+ | Type | Format | Used for |
45
+ |---|---|---|
46
+ | Regular | `kms_<id>.live_<secret>` | Email sending |
47
+ | Admin | `kms_<id>.adm_<secret>` | Contacts, audiences, automations, domains |
48
+
49
+ ## Email Sending
50
+
51
+ ### Priority Levels
52
+
53
+ | Method | Delivery | Use case |
54
+ |---|---|---|
55
+ | `send_instant` | 0–5 sec | OTPs, login codes, critical alerts |
56
+ | `send_high` | 0–30 sec | Transactional, notifications |
57
+ | `send_async` / `send` | 0–5 min | General transactional |
58
+ | `send_bulk` | Idle | Newsletters, marketing |
59
+
60
+ ### Send with Recipients
61
+
62
+ ```ruby
63
+ result = client.emails.send_high(
64
+ from: 'noreply@yourdomain.com',
65
+ to: [{ email: 'user@example.com', name: 'John Doe' }],
66
+ cc: [{ email: 'manager@example.com' }],
67
+ subject: 'Order Confirmation',
68
+ html: '<p>Your order has been confirmed</p>'
69
+ )
70
+ ```
71
+
72
+ ### Response Shape
73
+
74
+ ```ruby
75
+ result[:success] # true
76
+ result[:message] # 'Email queued'
77
+ result[:data][:job_id] # 'job_abc123'
78
+ result[:data][:priority] # 'high'
79
+ ```
80
+
81
+ ### Send with Template
82
+
83
+ ```ruby
84
+ result = client.emails.send(
85
+ from: 'noreply@yourdomain.com',
86
+ to: 'user@example.com',
87
+ subject: 'Password Reset',
88
+ template_id: 'tpl_reset_password',
89
+ template_data: {
90
+ name: 'John',
91
+ reset_link: 'https://example.com/reset/abc'
92
+ }
93
+ )
94
+ ```
95
+
96
+ ### Schedule Email
97
+
98
+ ```ruby
99
+ result = client.emails.schedule(
100
+ from: 'newsletter@yourdomain.com',
101
+ to: 'user@example.com',
102
+ subject: 'Your weekly digest',
103
+ html: '<p>Here is your weekly digest...</p>',
104
+ scheduled_for: '2026-06-01T09:00:00Z',
105
+ priority: 'bulk'
106
+ )
107
+ ```
108
+
109
+ ## Contacts (Admin API Key Required)
110
+
111
+ ```ruby
112
+ admin_client = Keplars::Client.new(api_key: 'kms_<workspaceId>.adm_<secret>')
113
+
114
+ admin_client.contacts.add(email: 'user@example.com', name: 'John Doe', audience_id: 'aud_abc123')
115
+
116
+ contact = admin_client.contacts.get('user@example.com')
117
+
118
+ contacts = admin_client.contacts.list(audience_id: 'aud_abc123', page: 1, limit: 20)
119
+
120
+ admin_client.contacts.update('user@example.com', name: 'Jane Doe')
121
+
122
+ admin_client.contacts.delete('user@example.com')
123
+ ```
124
+
125
+ ## Audiences (Admin API Key Required)
126
+
127
+ ```ruby
128
+ audience = admin_client.audiences.create(name: 'Newsletter Subscribers', description: 'Main list')
129
+
130
+ audiences = admin_client.audiences.list(page: 1, limit: 20)
131
+
132
+ audience = admin_client.audiences.get('aud_abc123')
133
+
134
+ admin_client.audiences.delete('aud_abc123')
135
+ ```
136
+
137
+ ## Automations (Admin API Key Required)
138
+
139
+ ```ruby
140
+ automations = admin_client.automations.list
141
+
142
+ automation = admin_client.automations.get('auto_abc123')
143
+
144
+ admin_client.automations.enroll('auto_abc123', email: 'user@example.com')
145
+
146
+ admin_client.automations.unenroll('auto_abc123', email: 'user@example.com')
147
+ ```
148
+
149
+ ## Domains (Admin API Key Required)
150
+
151
+ ```ruby
152
+ domain = admin_client.domains.add('mail.yourcompany.com')
153
+
154
+ domains = admin_client.domains.list
155
+
156
+ status = admin_client.domains.get_status('dom_abc123')
157
+
158
+ result = admin_client.domains.verify('dom_abc123')
159
+
160
+ api_key = admin_client.domains.create_api_key(domain_id: 'dom_abc123', name: 'Production Key')
161
+
162
+ admin_client.domains.delete('dom_abc123')
163
+ ```
164
+
165
+ ## Error Handling
166
+
167
+ ```ruby
168
+ require 'keplars'
169
+
170
+ begin
171
+ result = client.emails.send_instant(...)
172
+ rescue Keplars::AuthenticationError => e
173
+ puts "Invalid API key: #{e.message}"
174
+ rescue Keplars::RateLimitError => e
175
+ puts "Rate limited"
176
+ rescue Keplars::ValidationError => e
177
+ puts "Validation error: #{e.message}"
178
+ end
179
+ ```
@@ -0,0 +1,28 @@
1
+ module Keplars
2
+ module Resources
3
+ class Audiences < Base
4
+ def create(name:, description: nil)
5
+ body = { name: name }
6
+ body[:description] = description if description
7
+ @client.request('POST', '/api/v1/public/audiences/add-audience', body: body)[:data]
8
+ end
9
+
10
+ def list(page: nil, limit: nil)
11
+ params = {}
12
+ params[:page] = page if page
13
+ params[:limit] = limit if limit
14
+
15
+ query = @client.send(:build_query_string, params)
16
+ @client.request('GET', "/api/v1/public/audiences/get-audiences#{query}")[:data]
17
+ end
18
+
19
+ def get(id)
20
+ @client.request('GET', "/api/v1/public/audiences/get-audience?id=#{URI.encode_www_form_component(id)}")[:data]
21
+ end
22
+
23
+ def delete(id)
24
+ @client.request('DELETE', "/api/v1/public/audiences/delete-audience?id=#{URI.encode_www_form_component(id)}")[:data]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ module Keplars
2
+ module Resources
3
+ class Automations < Base
4
+ def list(page: nil, limit: nil)
5
+ params = {}
6
+ params[:page] = page if page
7
+ params[:limit] = limit if limit
8
+
9
+ query = @client.send(:build_query_string, params)
10
+ @client.request('GET', "/api/v1/public/automations/get-all#{query}")[:data]
11
+ end
12
+
13
+ def get(id)
14
+ @client.request('GET', "/api/v1/public/automations/get-automation/#{id}")[:data]
15
+ end
16
+
17
+ def enroll(id, email:)
18
+ @client.request('POST', "/api/v1/public/automations/add-automation/#{id}/enroll", body: { email: email })[:data]
19
+ end
20
+
21
+ def unenroll(id, email:)
22
+ @client.request('DELETE', "/api/v1/public/automations/delete-automation/#{id}/subscribers", body: { email: email })[:data]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,154 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'uri'
4
+
5
+ module Keplars
6
+ class Client
7
+ DEFAULT_BASE_URL = 'https://api.keplars.com'
8
+ DEFAULT_TIMEOUT = 30
9
+ DEFAULT_MAX_RETRIES = 3
10
+ DEFAULT_RETRY_DELAY = 1
11
+
12
+ attr_reader :emails, :contacts, :audiences, :automations, :domains
13
+
14
+ def initialize(api_key: nil, base_url: nil, timeout: DEFAULT_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES, retry_delay: DEFAULT_RETRY_DELAY)
15
+ @api_key = api_key || ENV['KEPLARS_API_KEY']
16
+ raise ArgumentError, 'API key is required. Set KEPLARS_API_KEY or pass api_key parameter' if @api_key.nil? || @api_key.empty?
17
+
18
+ unless validate_api_key(@api_key)
19
+ raise ArgumentError, 'Invalid API key format. Expected: kms_<id>.live_<secret> or kms_<id>.adm_<secret>'
20
+ end
21
+
22
+ resolved_base_url = base_url || ENV['KEPLARS_BASE_URL'] || DEFAULT_BASE_URL
23
+ @base_url = resolved_base_url.sub(/\/$/, '')
24
+ @timeout = timeout
25
+ @max_retries = max_retries
26
+ @retry_delay = retry_delay
27
+
28
+ @emails = Resources::Emails.new(self)
29
+ @contacts = Resources::Contacts.new(self)
30
+ @audiences = Resources::Audiences.new(self)
31
+ @automations = Resources::Automations.new(self)
32
+ @domains = Resources::Domains.new(self)
33
+ end
34
+
35
+ def request(method, path, body: nil, retry_count: 0)
36
+ uri = URI("#{@base_url}#{path}")
37
+
38
+ http = Net::HTTP.new(uri.host, uri.port)
39
+ http.use_ssl = uri.scheme == 'https'
40
+ http.read_timeout = @timeout
41
+ http.open_timeout = @timeout
42
+
43
+ request_class = case method.upcase
44
+ when 'GET' then Net::HTTP::Get
45
+ when 'POST' then Net::HTTP::Post
46
+ when 'PUT' then Net::HTTP::Put
47
+ when 'PATCH' then Net::HTTP::Patch
48
+ when 'DELETE' then Net::HTTP::Delete
49
+ else raise ArgumentError, "Unsupported HTTP method: #{method}"
50
+ end
51
+
52
+ request = request_class.new(uri.request_uri)
53
+ request['Authorization'] = "Bearer #{@api_key}"
54
+ request['Content-Type'] = 'application/json'
55
+ request['User-Agent'] = "keplars-ruby/#{VERSION}"
56
+
57
+ request.body = body.to_json if body
58
+
59
+ begin
60
+ response = http.request(request)
61
+ rate_limit_info = extract_rate_limit_info(response)
62
+
63
+ if response.code.to_i >= 400
64
+ handle_error_response(response, retry_count, method, path, body)
65
+ end
66
+
67
+ result = response.body && !response.body.empty? ? JSON.parse(response.body, symbolize_names: true) : nil
68
+ { data: result, rate_limit_info: rate_limit_info }
69
+ rescue StandardError => e
70
+ if retryable_error?(e) && retry_count < @max_retries
71
+ delay = calculate_backoff(retry_count)
72
+ sleep(delay)
73
+ request(method, path, body: body, retry_count: retry_count + 1)
74
+ else
75
+ raise NetworkError.new("Request failed: #{e.message}", original_error: e)
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def extract_rate_limit_info(response)
83
+ limit = response['X-RateLimit-Limit']
84
+ remaining = response['X-RateLimit-Remaining']
85
+ reset = response['X-RateLimit-Reset']
86
+
87
+ return nil unless limit && remaining && reset
88
+
89
+ {
90
+ limit: limit.to_i,
91
+ remaining: remaining.to_i,
92
+ reset: reset.to_i
93
+ }
94
+ end
95
+
96
+ def handle_error_response(response, retry_count, method, path, body)
97
+ error_data = JSON.parse(response.body, symbolize_names: true) rescue {}
98
+ status_code = response.code.to_i
99
+ message = error_data[:message] || "HTTP #{status_code}"
100
+
101
+ case status_code
102
+ when 400
103
+ raise ValidationError.new(message, details: nil, request_id: nil)
104
+ when 401
105
+ raise AuthenticationError.new(message, request_id: nil)
106
+ when 403
107
+ raise AuthorizationError.new(message, request_id: nil)
108
+ when 404
109
+ raise KeplarsError.new(message, code: 'NOT_FOUND', status_code: status_code)
110
+ when 409
111
+ raise KeplarsError.new(message, code: 'CONFLICT', status_code: status_code)
112
+ when 429
113
+ raise RateLimitError.new(message, retry_after: 60, request_id: nil)
114
+ else
115
+ if status_code >= 500
116
+ if retry_count < @max_retries
117
+ delay = calculate_backoff(retry_count)
118
+ sleep(delay)
119
+ end
120
+ raise InternalError.new(message, request_id: nil)
121
+ else
122
+ raise KeplarsError.new(message, code: 'UNKNOWN_ERROR', status_code: status_code)
123
+ end
124
+ end
125
+ end
126
+
127
+ def calculate_backoff(retry_count)
128
+ exponential_delay = @retry_delay * (2**retry_count)
129
+ jitter = rand * 0.3 * exponential_delay
130
+ [exponential_delay + jitter, 30].min
131
+ end
132
+
133
+ def retryable_error?(error)
134
+ error.is_a?(Timeout::Error) ||
135
+ error.is_a?(Errno::ECONNRESET) ||
136
+ error.is_a?(Errno::ETIMEDOUT) ||
137
+ error.is_a?(Errno::ECONNREFUSED)
138
+ end
139
+
140
+ def build_query_string(params)
141
+ return '' if params.nil? || params.empty?
142
+
143
+ filtered = params.reject { |_, v| v.nil? || v == '' }
144
+ return '' if filtered.empty?
145
+
146
+ query = filtered.map { |k, v| "#{k}=#{URI.encode_www_form_component(v)}" }.join('&')
147
+ "?#{query}"
148
+ end
149
+
150
+ def validate_api_key(api_key)
151
+ api_key.match?(/\Akms_[a-f0-9]+\.(live|adm)_[a-f0-9]+\z/)
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,31 @@
1
+ module Keplars
2
+ module Resources
3
+ class Contacts < Base
4
+ def add(**params)
5
+ @client.request('POST', '/api/v1/public/contacts/add-contact', body: params.compact)[:data]
6
+ end
7
+
8
+ def get(email)
9
+ @client.request('GET', "/api/v1/public/contacts/get-contact?email=#{URI.encode_www_form_component(email)}")[:data]
10
+ end
11
+
12
+ def list(audience_id: nil, page: nil, limit: nil)
13
+ params = {}
14
+ params[:audience_id] = audience_id if audience_id
15
+ params[:page] = page if page
16
+ params[:limit] = limit if limit
17
+
18
+ query = @client.send(:build_query_string, params)
19
+ @client.request('GET', "/api/v1/public/contacts/get-contacts#{query}")[:data]
20
+ end
21
+
22
+ def update(email, **params)
23
+ @client.request('PATCH', "/api/v1/public/contacts/update-contact?email=#{URI.encode_www_form_component(email)}", body: params.compact)[:data]
24
+ end
25
+
26
+ def delete(email)
27
+ @client.request('DELETE', "/api/v1/public/contacts/delete-contact?email=#{URI.encode_www_form_component(email)}")[:data]
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ module Keplars
2
+ module Resources
3
+ class Domains < Base
4
+ def add(domain)
5
+ @client.request('POST', '/api/v1/public/domains/add-domain', body: { domain: domain })[:data]
6
+ end
7
+
8
+ def list
9
+ @client.request('GET', '/api/v1/public/domains/get-domains')[:data]
10
+ end
11
+
12
+ def get_status(domain_id)
13
+ @client.request('GET', "/api/v1/public/domains/domain-status/#{domain_id}")[:data]
14
+ end
15
+
16
+ def verify(domain_id)
17
+ @client.request('POST', "/api/v1/public/domains/verify-domain/#{domain_id}")[:data]
18
+ end
19
+
20
+ def delete(domain_id)
21
+ @client.request('DELETE', "/api/v1/public/domains/delete-domain/#{domain_id}")[:data]
22
+ end
23
+
24
+ def create_api_key(**params)
25
+ @client.request('POST', '/api/v1/public/domains/api-keys/create', body: params.compact)[:data]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ module Keplars
2
+ class KeplarsError < StandardError
3
+ attr_reader :code, :request_id, :status_code
4
+
5
+ def initialize(message, code: nil, request_id: nil, status_code: nil)
6
+ super(message)
7
+ @code = code
8
+ @request_id = request_id
9
+ @status_code = status_code
10
+ end
11
+ end
12
+
13
+ class ValidationError < KeplarsError
14
+ attr_reader :details
15
+
16
+ def initialize(message, details: nil, request_id: nil)
17
+ super(message, code: 'VALIDATION_ERROR', request_id: request_id)
18
+ @details = details
19
+ end
20
+ end
21
+
22
+ class AuthenticationError < KeplarsError
23
+ def initialize(message, request_id: nil)
24
+ super(message, code: 'AUTHENTICATION_ERROR', request_id: request_id)
25
+ end
26
+ end
27
+
28
+ class AuthorizationError < KeplarsError
29
+ def initialize(message, request_id: nil)
30
+ super(message, code: 'AUTHORIZATION_ERROR', request_id: request_id)
31
+ end
32
+ end
33
+
34
+ class DomainNotVerifiedError < KeplarsError
35
+ attr_reader :domain, :verification_status
36
+
37
+ def initialize(message, domain:, verification_status:, request_id: nil)
38
+ super(message, code: 'DOMAIN_NOT_VERIFIED', request_id: request_id)
39
+ @domain = domain
40
+ @verification_status = verification_status
41
+ end
42
+ end
43
+
44
+ class RateLimitError < KeplarsError
45
+ attr_reader :retry_after
46
+
47
+ def initialize(message, retry_after:, request_id: nil)
48
+ super(message, code: 'RATE_LIMIT_EXCEEDED', request_id: request_id)
49
+ @retry_after = retry_after
50
+ end
51
+ end
52
+
53
+ class InternalError < KeplarsError
54
+ def initialize(message, request_id: nil)
55
+ super(message, code: 'INTERNAL_ERROR', request_id: request_id)
56
+ end
57
+ end
58
+
59
+ class NetworkError < KeplarsError
60
+ def initialize(message, original_error: nil)
61
+ super(message, code: 'NETWORK_ERROR')
62
+ @original_error = original_error
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,41 @@
1
+ module Keplars
2
+ module Resources
3
+ class Base
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+ end
8
+
9
+ class Emails < Base
10
+ def send_instant(**args)
11
+ body = args.compact
12
+ @client.request('POST', '/api/v1/public/send-email/instant', body: body)[:data]
13
+ end
14
+
15
+ def send_high(**args)
16
+ body = args.compact
17
+ @client.request('POST', '/api/v1/public/send-email/high', body: body)[:data]
18
+ end
19
+
20
+ def send_async(**args)
21
+ body = args.compact
22
+ @client.request('POST', '/api/v1/public/send-email/async', body: body)[:data]
23
+ end
24
+
25
+ def send_bulk(**args)
26
+ body = args.compact
27
+ @client.request('POST', '/api/v1/public/send-email/bulk', body: body)[:data]
28
+ end
29
+
30
+ def send(**args)
31
+ send_async(**args)
32
+ end
33
+
34
+ def schedule(**args)
35
+ body = args.compact
36
+ body[:priority] ||= 'async'
37
+ @client.request('POST', '/api/v1/public/send-email/schedule', body: body)[:data]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module Keplars
2
+ VERSION = "1.0.0"
3
+ end
data/lib/keplars.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'uri'
4
+
5
+ require_relative 'keplars/version'
6
+ require_relative 'keplars/errors'
7
+ require_relative 'keplars/resources'
8
+ require_relative 'keplars/contacts'
9
+ require_relative 'keplars/audiences'
10
+ require_relative 'keplars/automations'
11
+ require_relative 'keplars/domains'
12
+ require_relative 'keplars/client'
13
+
14
+ module Keplars
15
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: keplars
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Keplars
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2026-05-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday-retry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.19'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.19'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.59'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.59'
83
+ description: Modern transactional email service SDK with priority-based delivery for
84
+ Ruby
85
+ email:
86
+ - support@keplars.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - Gemfile
92
+ - README.md
93
+ - lib/keplars.rb
94
+ - lib/keplars/audiences.rb
95
+ - lib/keplars/automations.rb
96
+ - lib/keplars/client.rb
97
+ - lib/keplars/contacts.rb
98
+ - lib/keplars/domains.rb
99
+ - lib/keplars/errors.rb
100
+ - lib/keplars/resources.rb
101
+ - lib/keplars/version.rb
102
+ homepage: https://keplars.com
103
+ licenses:
104
+ - MIT
105
+ metadata:
106
+ homepage_uri: https://keplars.com
107
+ source_code_uri: https://github.com/Swing-Technologies/keplars-email-sdk
108
+ changelog_uri: https://github.com/Swing-Technologies/keplars-email-sdk/blob/main/CHANGELOG.md
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 3.0.0
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 3.4.19
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Official Ruby SDK for Keplars Email API
128
+ test_files: []