utobo-email 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 +7 -0
- data/README.md +50 -0
- data/lib/utobo_email/client.rb +69 -0
- data/lib/utobo_email/emails.rb +45 -0
- data/lib/utobo_email/errors.rb +19 -0
- data/lib/utobo_email.rb +11 -0
- metadata +51 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9f99b1c98483d5c62504904bd4cbb735d1a50e8260f98b2f6926897d852a0b89
|
|
4
|
+
data.tar.gz: 5fe4c2dfb7c4fe3b1a891db293a9703e867baa9acf644ab850f29b2faabc269c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7923f8b1cbc0b50825859fae50aa278acfecdc8bda4308f7604d7c66e2998cb0387403b6af9d1d38d92bc2bd2224c4024ab77fb864df13e9293f59d97e01f1dd
|
|
7
|
+
data.tar.gz: 2e4bcb8efab5946163cdc638781b5d98800ae5203228480a9473d9889db89ff48b6097fa382f4dd79a18e54adc6087ba3110ab713a40d5f079ca1146a58180ad
|
data/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# utobo-email
|
|
2
|
+
|
|
3
|
+
Official Ruby SDK for the [utobo email](https://utobo.com/email) email platform.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
gem install utobo-email
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or add to your Gemfile:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem "utobo-email"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quickstart
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
require "utobo_email"
|
|
21
|
+
|
|
22
|
+
client = UtoboEmail.new("av_live_...")
|
|
23
|
+
|
|
24
|
+
result = client.emails.send(
|
|
25
|
+
from: "Acme <noreply@acme.com>",
|
|
26
|
+
to: "user@example.com",
|
|
27
|
+
subject: "Welcome!",
|
|
28
|
+
html: "<p>Welcome to Acme!</p>"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
puts result["id"]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Check delivery status
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
status = client.emails.get("3c9b0f4e-...")
|
|
38
|
+
puts status["status"] # "sent" | "failed"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
|
|
43
|
+
| Option | Env var | Default |
|
|
44
|
+
|--------|---------|---------|
|
|
45
|
+
| `api_key` (1st arg) | `UTOBO_EMAIL_API_KEY` | — (required) |
|
|
46
|
+
| `base_url:` | `UTOBO_EMAIL_BASE_URL` | `https://api.email.utobo.com/v1` |
|
|
47
|
+
|
|
48
|
+
## License
|
|
49
|
+
|
|
50
|
+
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
require "uri"
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module UtoboEmail
|
|
6
|
+
class Client
|
|
7
|
+
DEFAULT_BASE_URL = "https://api.email.utobo.com/v1"
|
|
8
|
+
SDK_VERSION = "1.0.0"
|
|
9
|
+
|
|
10
|
+
attr_reader :emails
|
|
11
|
+
|
|
12
|
+
def initialize(api_key = nil, base_url: nil)
|
|
13
|
+
@api_key = api_key || ENV["UTOBO_EMAIL_API_KEY"] || ENV["UTOBO_MAIL_API_KEY"]
|
|
14
|
+
raise ArgumentError, <<~MSG.strip if @api_key.nil? || @api_key.empty?
|
|
15
|
+
Missing API key. Pass it to UtoboEmail.new("av_live_...") or set UTOBO_EMAIL_API_KEY.
|
|
16
|
+
MSG
|
|
17
|
+
|
|
18
|
+
@base_url = base_url || ENV["UTOBO_EMAIL_BASE_URL"] || ENV["UTOBO_MAIL_BASE_URL"] || DEFAULT_BASE_URL
|
|
19
|
+
@emails = Emails.new(self)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @api private
|
|
23
|
+
def post(path, body)
|
|
24
|
+
uri = URI("#{@base_url}#{path}")
|
|
25
|
+
req = Net::HTTP::Post.new(uri)
|
|
26
|
+
set_headers(req)
|
|
27
|
+
req.body = JSON.generate(body)
|
|
28
|
+
execute(uri, req)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @api private
|
|
32
|
+
def get(path)
|
|
33
|
+
uri = URI("#{@base_url}#{path}")
|
|
34
|
+
req = Net::HTTP::Get.new(uri)
|
|
35
|
+
set_headers(req)
|
|
36
|
+
execute(uri, req)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def set_headers(req)
|
|
42
|
+
req["Authorization"] = "Bearer #{@api_key}"
|
|
43
|
+
req["Content-Type"] = "application/json"
|
|
44
|
+
req["User-Agent"] = "utobo-email-ruby/#{SDK_VERSION}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def execute(uri, req)
|
|
48
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
49
|
+
http.use_ssl = (uri.scheme == "https")
|
|
50
|
+
http.open_timeout = 10
|
|
51
|
+
http.read_timeout = 30
|
|
52
|
+
|
|
53
|
+
resp = http.request(req)
|
|
54
|
+
body = JSON.parse(resp.body) rescue {}
|
|
55
|
+
|
|
56
|
+
if resp.code.to_i >= 400
|
|
57
|
+
raise ApiError.new(
|
|
58
|
+
status_code: resp.code.to_i,
|
|
59
|
+
name: body["name"] || "api_error",
|
|
60
|
+
message: body["message"] || "Request failed"
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
body
|
|
65
|
+
rescue SocketError, Errno::ECONNREFUSED, Net::OpenTimeout, Net::ReadTimeout => e
|
|
66
|
+
raise NetworkError, e.message
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module UtoboEmail
|
|
2
|
+
class Emails
|
|
3
|
+
def initialize(client)
|
|
4
|
+
@client = client
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Send a transactional email.
|
|
8
|
+
#
|
|
9
|
+
# @param from [String] Sender address ("Name <email>" format)
|
|
10
|
+
# @param to [String, Array<String>] Recipient(s)
|
|
11
|
+
# @param subject [String] Email subject
|
|
12
|
+
# @param html [String, nil] HTML body
|
|
13
|
+
# @param text [String, nil] Plain-text body
|
|
14
|
+
# @param reply_to [String, Array<String>, nil]
|
|
15
|
+
# @param cc [String, Array<String>, nil]
|
|
16
|
+
# @param bcc [String, Array<String>, nil]
|
|
17
|
+
# @param attachments [Array<Hash>, nil] Each hash requires :filename and :content (base64), optional :contentType
|
|
18
|
+
# @param headers [Hash, nil] Custom email headers
|
|
19
|
+
# @return [Hash] { "id" => "...", "message" => "..." }
|
|
20
|
+
def send(from:, to:, subject:, html: nil, text: nil, reply_to: nil, cc: nil, bcc: nil, attachments: nil, headers: nil)
|
|
21
|
+
body = {
|
|
22
|
+
from: from,
|
|
23
|
+
to: Array(to),
|
|
24
|
+
subject: subject,
|
|
25
|
+
}
|
|
26
|
+
body[:html] = html if html
|
|
27
|
+
body[:text] = text if text
|
|
28
|
+
body[:reply_to] = Array(reply_to) if reply_to
|
|
29
|
+
body[:cc] = Array(cc) if cc
|
|
30
|
+
body[:bcc] = Array(bcc) if bcc
|
|
31
|
+
body[:attachments] = attachments if attachments
|
|
32
|
+
body[:headers] = headers if headers
|
|
33
|
+
|
|
34
|
+
@client.post("/send-email", body)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Retrieve the status of a previously sent email.
|
|
38
|
+
#
|
|
39
|
+
# @param id [String] The email ID returned by send()
|
|
40
|
+
# @return [Hash] { "id", "from", "to", "subject", "status", "ses_message_id", "created_at" }
|
|
41
|
+
def get(id)
|
|
42
|
+
@client.get("/send-email/#{id}")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module UtoboEmail
|
|
2
|
+
class Error < StandardError; end
|
|
3
|
+
|
|
4
|
+
class ApiError < Error
|
|
5
|
+
attr_reader :status_code, :name
|
|
6
|
+
|
|
7
|
+
def initialize(status_code:, name:, message:)
|
|
8
|
+
@status_code = status_code
|
|
9
|
+
@name = name
|
|
10
|
+
super("#{name} (#{status_code}): #{message}")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class NetworkError < Error
|
|
15
|
+
def initialize(msg = "Unable to reach the utobo email API")
|
|
16
|
+
super(msg)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/utobo_email.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require_relative "utobo_email/client"
|
|
2
|
+
require_relative "utobo_email/emails"
|
|
3
|
+
require_relative "utobo_email/errors"
|
|
4
|
+
|
|
5
|
+
module UtoboEmail
|
|
6
|
+
VERSION = "1.0.0"
|
|
7
|
+
|
|
8
|
+
def self.new(api_key = nil, base_url: nil)
|
|
9
|
+
Client.new(api_key, base_url: base_url)
|
|
10
|
+
end
|
|
11
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: utobo-email
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Utobo
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-09 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Send transactional emails and check delivery status via the utobo email
|
|
14
|
+
API.
|
|
15
|
+
email: hello@mail.utobo.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- README.md
|
|
21
|
+
- lib/utobo_email.rb
|
|
22
|
+
- lib/utobo_email/client.rb
|
|
23
|
+
- lib/utobo_email/emails.rb
|
|
24
|
+
- lib/utobo_email/errors.rb
|
|
25
|
+
homepage: https://utobo.com/email
|
|
26
|
+
licenses:
|
|
27
|
+
- MIT
|
|
28
|
+
metadata:
|
|
29
|
+
source_code_uri: https://github.com/myutobo/utobo-email-ruby
|
|
30
|
+
bug_tracker_uri: https://github.com/myutobo/utobo-email-ruby/issues
|
|
31
|
+
documentation_uri: https://utobo.com/email/docs
|
|
32
|
+
post_install_message:
|
|
33
|
+
rdoc_options: []
|
|
34
|
+
require_paths:
|
|
35
|
+
- lib
|
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.0'
|
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
requirements: []
|
|
47
|
+
rubygems_version: 3.0.3.1
|
|
48
|
+
signing_key:
|
|
49
|
+
specification_version: 4
|
|
50
|
+
summary: Official Ruby SDK for the utobo email Email Platform
|
|
51
|
+
test_files: []
|