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 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
@@ -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: []