resend 0.2.1 → 0.4.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 +18 -6
- data/lib/resend/api_keys.rb +29 -0
- data/lib/resend/client.rb +11 -52
- data/lib/resend/domains.rb +35 -0
- data/lib/resend/emails.rb +29 -0
- data/lib/resend/errors.rb +33 -2
- data/lib/resend/mailer.rb +53 -16
- data/lib/resend/railtie.rb +4 -1
- data/lib/resend/request.rb +48 -0
- data/lib/resend/version.rb +1 -1
- data/lib/resend.rb +6 -4
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3e46d09490b1ad19c59f04e55fd16b0da3d3c2573ed5c9dcba3297f0f92f5fc
|
4
|
+
data.tar.gz: 6c9dfb7910fd6199bc9c75aa9f3c2e9200677ce9e2ba1e9a29e124908489e714
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58e0cdd7ae1d48654ff33761b1fcb8a4e96061142d154232f85bac348c38956505d11ee3a0cdf6d86592389d2d8c69eba48941d7d97e1c4de904d0c8b5b6d7a6
|
7
|
+
data.tar.gz: 2069dfd99a67245da05ebf8e58658c2771de51cd6999d8d824116174b0aeba38dcc4f4423f05cb73e63388f5497377dba4c4b98eebddba2b2205864530790d3a
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ gem install resend
|
|
16
16
|
|
17
17
|
Via Gemfile:
|
18
18
|
```
|
19
|
-
gem 'resend', '~>0.
|
19
|
+
gem 'resend', '~>0.3.0'
|
20
20
|
```
|
21
21
|
|
22
22
|
## Setup
|
@@ -25,7 +25,16 @@ First, you need to get an API key, which is available in the [Resend Dashboard](
|
|
25
25
|
|
26
26
|
```ruby
|
27
27
|
require "resend"
|
28
|
-
|
28
|
+
Resend.api_key = ENV["RESEND_API_KEY"]
|
29
|
+
```
|
30
|
+
|
31
|
+
or
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
require "resend"
|
35
|
+
Resend.configure do |config|
|
36
|
+
config.api_key = ENV["RESEND_API_KEY"]
|
37
|
+
end
|
29
38
|
```
|
30
39
|
|
31
40
|
## Example
|
@@ -33,18 +42,21 @@ client = Resend::Client.new "re_YOUR_API_KEY"
|
|
33
42
|
```rb
|
34
43
|
require "resend"
|
35
44
|
|
36
|
-
|
45
|
+
Resend.api_key = ENV["RESEND_API_KEY"]
|
37
46
|
|
38
47
|
params = {
|
39
|
-
"from": "
|
40
|
-
"to": "
|
48
|
+
"from": "from@email.io",
|
49
|
+
"to": ["to@email.com", "to1@gmail.com"],
|
41
50
|
"html": "<h1>Hello World</h1>",
|
42
51
|
"subject": "Hey"
|
43
52
|
}
|
44
|
-
r =
|
53
|
+
r = Resend::Emails.send(params)
|
45
54
|
puts r
|
46
55
|
```
|
47
56
|
|
57
|
+
You can view all the examples in the [examples folder](https://github.com/drish/resend-ruby/tree/main/examples)
|
58
|
+
|
59
|
+
|
48
60
|
# Rails and ActiveMailer support
|
49
61
|
|
50
62
|
This gem can be used as an ActionMailer delivery method, add this to your `config/environments/environment.rb` file and replace with your api key.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "resend/request"
|
4
|
+
require "resend/errors"
|
5
|
+
|
6
|
+
module Resend
|
7
|
+
# api keys api wrapper
|
8
|
+
module ApiKeys
|
9
|
+
class << self
|
10
|
+
# https://resend.com/docs/api-reference/api-keys/create-api-key
|
11
|
+
def create(params)
|
12
|
+
path = "/api-keys"
|
13
|
+
Resend::Request.new(path, params, "post").perform
|
14
|
+
end
|
15
|
+
|
16
|
+
# https://resend.com/docs/api-reference/api-keys/list-api-keys
|
17
|
+
def list
|
18
|
+
path = "/api-keys"
|
19
|
+
Resend::Request.new(path, {}, "get").perform
|
20
|
+
end
|
21
|
+
|
22
|
+
# https://resend.com/docs/api-reference/api-keys/delete-api-key
|
23
|
+
def remove(api_key_id = "")
|
24
|
+
path = "/api-keys/#{api_key_id}"
|
25
|
+
Resend::Request.new(path, {}, "delete").perform
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/resend/client.rb
CHANGED
@@ -1,62 +1,21 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "resend/api_keys"
|
4
|
+
require "resend/domains"
|
5
|
+
require "resend/emails"
|
3
6
|
require "httparty"
|
4
7
|
|
5
8
|
module Resend
|
6
|
-
|
9
|
+
# Client class.
|
7
10
|
class Client
|
8
|
-
|
11
|
+
include Resend::Emails
|
9
12
|
|
10
|
-
attr_reader :api_key
|
13
|
+
attr_reader :api_key
|
11
14
|
|
12
15
|
def initialize(api_key)
|
13
|
-
raise ArgumentError
|
14
|
-
@api_key = api_key
|
15
|
-
@timeout = nil
|
16
|
-
end
|
17
|
-
|
18
|
-
def send_email(params)
|
19
|
-
validate!(params)
|
20
|
-
|
21
|
-
options = {
|
22
|
-
headers: {
|
23
|
-
'Content-Type' => 'application/json',
|
24
|
-
"Accept" => "application/json",
|
25
|
-
"User-Agent" => "ruby:#{Resend::VERSION}",
|
26
|
-
"Authorization" => "Bearer #{@api_key}",
|
27
|
-
},
|
28
|
-
body: params.to_json
|
29
|
-
}
|
30
|
-
|
31
|
-
resp = HTTParty.post("#{BASE_URL}/email", options)
|
32
|
-
resp.transform_keys!(&:to_sym)
|
33
|
-
if not resp[:error].nil?
|
34
|
-
handle_error!(resp[:error])
|
35
|
-
end
|
36
|
-
resp
|
37
|
-
end
|
16
|
+
raise ArgumentError, "API Key is not a string" unless api_key.is_a?(String)
|
38
17
|
|
39
|
-
|
40
|
-
|
41
|
-
def validate!(params)
|
42
|
-
raise ArgumentError.new("'to' should be an Array or String") unless params[:to].is_a?(String) or params[:to].is_a?(Array)
|
43
|
-
raise ArgumentError.new("Argument 'to' is missing") if params[:to].nil?
|
44
|
-
raise ArgumentError.new("'to' can not be empty") if params[:to].empty?
|
45
|
-
|
46
|
-
raise ArgumentError.new("'from' should be a String") unless params[:from].is_a?(String)
|
47
|
-
raise ArgumentError.new("Argument 'from' is missing") if params[:from].nil?
|
48
|
-
raise ArgumentError.new("'from' can not be empty") if params[:from].empty?
|
49
|
-
|
50
|
-
raise ArgumentError.new("'from' should be a String") unless params[:from].is_a?(String)
|
51
|
-
raise ArgumentError.new("Argument 'subject' is missing") if params[:subject].nil?
|
52
|
-
raise ArgumentError.new("'subject' can not be empty") if params[:subject].empty?
|
53
|
-
|
54
|
-
raise ArgumentError.new("Argument 'text' and 'html' are missing") if params[:text].nil? and params[:html].nil?
|
55
|
-
end
|
56
|
-
|
57
|
-
def handle_error!(error)
|
58
|
-
err = error.transform_keys(&:to_sym)
|
59
|
-
raise Resend::ResendError.new(err[:message])
|
18
|
+
@api_key = api_key
|
60
19
|
end
|
61
20
|
end
|
62
|
-
end
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "resend/request"
|
4
|
+
require "resend/errors"
|
5
|
+
|
6
|
+
module Resend
|
7
|
+
# domains api wrapper
|
8
|
+
module Domains
|
9
|
+
class << self
|
10
|
+
# https://resend.com/docs/api-reference/domains/create-domain
|
11
|
+
def create(params)
|
12
|
+
path = "/domains"
|
13
|
+
Resend::Request.new(path, params, "post").perform
|
14
|
+
end
|
15
|
+
|
16
|
+
# https://resend.com/docs/api-reference/api-keys/list-api-keys
|
17
|
+
def list
|
18
|
+
path = "/domains"
|
19
|
+
Resend::Request.new(path, {}, "get").perform
|
20
|
+
end
|
21
|
+
|
22
|
+
# https://resend.com/docs/api-reference/domains/delete-domain
|
23
|
+
def remove(domain_id = "")
|
24
|
+
path = "/domains/#{domain_id}"
|
25
|
+
Resend::Request.new(path, {}, "delete").perform
|
26
|
+
end
|
27
|
+
|
28
|
+
# https://resend.com/docs/api-reference/domains/verify-domain
|
29
|
+
def verify(domain_id = "")
|
30
|
+
path = "/domains/#{domain_id}/verify"
|
31
|
+
Resend::Request.new(path, {}, "post").perform
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "resend/request"
|
4
|
+
|
5
|
+
module Resend
|
6
|
+
# Module responsible for wrapping email sending API
|
7
|
+
module Emails
|
8
|
+
class << self
|
9
|
+
# send email functionality
|
10
|
+
# https://resend.com/docs/api-reference/send-email
|
11
|
+
def send(params)
|
12
|
+
path = "emails"
|
13
|
+
Resend::Request.new(path, params, "post").perform
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(email_id = "")
|
17
|
+
path = "emails/#{email_id}"
|
18
|
+
Resend::Request.new(path, {}, "get").perform
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# This method is kept here for backwards compatibility
|
23
|
+
# Use Resend::Emails.send instead.
|
24
|
+
def send_email(params)
|
25
|
+
warn "[DEPRECATION] `send_email` is deprecated. Please use `Resend::Emails.send` instead."
|
26
|
+
Resend::Emails.send(params)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/resend/errors.rb
CHANGED
@@ -1,5 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Resend
|
2
|
-
|
4
|
+
# Errors wrapper class
|
5
|
+
# For more info: https://resend.com/docs/api-reference/error-codes
|
6
|
+
class Error < StandardError
|
7
|
+
|
8
|
+
# 4xx HTTP status code
|
9
|
+
ClientError = Class.new(self)
|
10
|
+
|
11
|
+
# 5xx HTTP status code
|
12
|
+
ServerError = Class.new(self)
|
13
|
+
|
14
|
+
# code 500
|
15
|
+
InternalServerError = Class.new(ServerError)
|
16
|
+
|
17
|
+
# code 422
|
18
|
+
InvalidRequestError = Class.new(ServerError)
|
19
|
+
|
20
|
+
# code 404
|
21
|
+
NotFoundError = Class.new(ServerError)
|
22
|
+
|
23
|
+
ERRORS = {
|
24
|
+
401 => Resend::Error::InvalidRequestError,
|
25
|
+
404 => Resend::Error::InvalidRequestError,
|
26
|
+
422 => Resend::Error::InvalidRequestError,
|
27
|
+
400 => Resend::Error::InvalidRequestError,
|
28
|
+
500 => Resend::Error::InternalServerError
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
def initialize(msg, code = nil)
|
32
|
+
super(msg)
|
33
|
+
@code = code
|
34
|
+
end
|
3
35
|
end
|
4
36
|
end
|
5
|
-
|
data/lib/resend/mailer.rb
CHANGED
@@ -1,39 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "resend"
|
2
4
|
|
3
5
|
module Resend
|
6
|
+
# Mailer class used by railtie
|
4
7
|
class Mailer
|
5
|
-
|
6
8
|
attr_accessor :config, :settings
|
7
9
|
|
8
10
|
def initialize(config)
|
9
11
|
@config = config
|
10
|
-
raise Resend::ResendError.new("Config requires api_key", @config) unless @config.
|
12
|
+
raise Resend::ResendError.new("Config requires api_key", @config) unless @config.key?(:api_key)
|
13
|
+
|
11
14
|
@settings = { return_response: true } # avoids NilError exception
|
12
|
-
@resend_client = Resend::Client.new config[:api_key]
|
13
15
|
end
|
14
16
|
|
15
17
|
def deliver!(mail)
|
18
|
+
params = build_resend_params(mail)
|
19
|
+
resp = Resend::Emails.send(params)
|
20
|
+
mail.message_id = resp[:id] if resp[:error].nil?
|
21
|
+
resp
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_resend_params(mail)
|
16
25
|
params = {
|
17
|
-
from: mail
|
26
|
+
from: get_from(mail.from),
|
18
27
|
to: mail.to,
|
19
|
-
subject: mail.subject
|
28
|
+
subject: mail.subject
|
20
29
|
}
|
21
|
-
params
|
22
|
-
params[:
|
23
|
-
params
|
24
|
-
params
|
30
|
+
params.merge!(get_addons(mail))
|
31
|
+
params[:attachments] = get_attachments(mail) if mail.attachments.present?
|
32
|
+
params.merge!(get_contents(mail))
|
33
|
+
params
|
34
|
+
end
|
25
35
|
|
26
|
-
|
36
|
+
def get_addons(mail)
|
37
|
+
params = {}
|
38
|
+
params[:cc] = mail.cc if mail.cc.present?
|
39
|
+
params[:bcc] = mail.bcc if mail.bcc.present?
|
40
|
+
params[:reply_to] = mail.reply_to if mail.reply_to.present?
|
41
|
+
params
|
42
|
+
end
|
27
43
|
|
28
|
-
|
29
|
-
|
44
|
+
def get_contents(mail)
|
45
|
+
params = {}
|
46
|
+
case mail.mime_type
|
47
|
+
when "text/plain"
|
48
|
+
params[:text] = mail.body.decoded
|
49
|
+
when "text/html"
|
50
|
+
params[:html] = mail.body.decoded
|
51
|
+
when "multipart/alternative", "multipart/mixed", "multipart/related"
|
52
|
+
params[:text] = mail.text_part.decoded if mail.text_part
|
53
|
+
params[:html] = mail.html_part.decoded if mail.html_part
|
30
54
|
end
|
55
|
+
params
|
56
|
+
end
|
31
57
|
|
32
|
-
|
58
|
+
def get_from(input)
|
59
|
+
return input.first if input.is_a? Array
|
60
|
+
|
61
|
+
input
|
33
62
|
end
|
34
63
|
|
35
|
-
def
|
36
|
-
|
64
|
+
def get_attachments(mail)
|
65
|
+
attachments = []
|
66
|
+
mail.attachments.each do |part|
|
67
|
+
attachment = {
|
68
|
+
filename: part.filename,
|
69
|
+
content: part.body.decoded.bytes
|
70
|
+
}
|
71
|
+
attachments.append(attachment)
|
72
|
+
end
|
73
|
+
attachments
|
37
74
|
end
|
38
75
|
end
|
39
|
-
end
|
76
|
+
end
|
data/lib/resend/railtie.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "resend"
|
2
4
|
require "resend/mailer"
|
3
5
|
|
4
6
|
module Resend
|
7
|
+
# Main railtime class
|
5
8
|
class Railtie < ::Rails::Railtie
|
6
9
|
ActiveSupport.on_load(:action_mailer) do
|
7
10
|
add_delivery_method :resend, Resend::Mailer
|
8
11
|
ActiveSupport.run_load_hooks(:resend_mailer, Resend::Mailer)
|
9
12
|
end
|
10
13
|
end
|
11
|
-
end
|
14
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "resend/version"
|
4
|
+
require "resend/errors"
|
5
|
+
require "httparty"
|
6
|
+
|
7
|
+
module Resend
|
8
|
+
# This class is responsible for making the appropriate HTTP calls
|
9
|
+
# and raising the specific errors based on the response.
|
10
|
+
class Request
|
11
|
+
BASE_URL = "https://api.resend.com/"
|
12
|
+
|
13
|
+
attr_accessor :body, :verb
|
14
|
+
|
15
|
+
def initialize(path = "", body = {}, verb = "POST")
|
16
|
+
raise if Resend.api_key.nil?
|
17
|
+
|
18
|
+
@path = path
|
19
|
+
@body = body
|
20
|
+
@verb = verb
|
21
|
+
@headers = {
|
22
|
+
"Content-Type" => "application/json",
|
23
|
+
"Accept" => "application/json",
|
24
|
+
"User-Agent" => "ruby:#{Resend::VERSION}",
|
25
|
+
"Authorization" => "Bearer #{Resend.api_key}"
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Performs the HTTP call
|
30
|
+
def perform
|
31
|
+
options = {
|
32
|
+
headers: @headers
|
33
|
+
}
|
34
|
+
options[:body] = @body.to_json unless @body.empty?
|
35
|
+
resp = HTTParty.send(@verb.to_sym, "#{BASE_URL}#{@path}", options)
|
36
|
+
resp.transform_keys!(&:to_sym) unless resp.body.empty?
|
37
|
+
handle_error!(resp) if resp[:statusCode] && resp[:statusCode] != 200
|
38
|
+
resp
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_error!(resp)
|
42
|
+
code = resp[:statusCode]
|
43
|
+
body = resp[:message]
|
44
|
+
error = Resend::Error::ERRORS[code]
|
45
|
+
raise(error.new(body, code)) if error
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/resend/version.rb
CHANGED
data/lib/resend.rb
CHANGED
@@ -3,15 +3,17 @@
|
|
3
3
|
require "resend/version"
|
4
4
|
require "resend/client"
|
5
5
|
|
6
|
-
require
|
6
|
+
require "resend/railtie" if defined?(Rails) && defined?(ActionMailer)
|
7
7
|
|
8
|
+
# Main Resend module
|
8
9
|
module Resend
|
9
10
|
class << self
|
10
|
-
attr_accessor :api_key
|
11
|
+
attr_accessor :api_key
|
12
|
+
|
11
13
|
def configure
|
12
14
|
yield self if block_given?
|
13
15
|
true
|
14
16
|
end
|
15
|
-
|
17
|
+
alias config configure
|
16
18
|
end
|
17
|
-
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resend
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derich Pacheco
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.19.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.19.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rails
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -46,12 +46,16 @@ extra_rdoc_files: []
|
|
46
46
|
files:
|
47
47
|
- README.md
|
48
48
|
- lib/resend.rb
|
49
|
+
- lib/resend/api_keys.rb
|
49
50
|
- lib/resend/client.rb
|
51
|
+
- lib/resend/domains.rb
|
52
|
+
- lib/resend/emails.rb
|
50
53
|
- lib/resend/errors.rb
|
51
54
|
- lib/resend/mailer.rb
|
52
55
|
- lib/resend/railtie.rb
|
56
|
+
- lib/resend/request.rb
|
53
57
|
- lib/resend/version.rb
|
54
|
-
homepage: https://github.com/
|
58
|
+
homepage: https://github.com/resendlabs/resend-ruby
|
55
59
|
licenses:
|
56
60
|
- MIT
|
57
61
|
metadata: {}
|