unosend 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: 609c63dd5cc0619946cd6a352c91bd010617545e25e7ca30483b696ec6b33118
4
+ data.tar.gz: 2e5b0b3a9355eda0b2a1868881df40a63f6077594cd4ee89bba7cf667157dafa
5
+ SHA512:
6
+ metadata.gz: ed43235228610ad7e494f7b3f1a620afa81684402f018a35eaa3ce4744abf18c49b15f32fab90b4b5b49822dfed8410c62e0ad1fb02759a6c7976e3296dabcca
7
+ data.tar.gz: 26495f31288524001076be96464d2d1ecec193371b994f7494499afd4f95d12baa034c79fe76554de53147ae331915c2ba8a4cd81a42b825ed8fae2d3245dc8d
data/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # unosend
2
+
3
+ Official Ruby SDK for [Unosend](https://unosend.co) - Email API Service.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'unosend'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install it directly:
20
+
21
+ ```bash
22
+ gem install unosend
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```ruby
28
+ require 'unosend'
29
+
30
+ client = Unosend::Client.new('un_your_api_key')
31
+
32
+ # Send an email
33
+ email = client.emails.send(
34
+ from: 'hello@yourdomain.com',
35
+ to: 'user@example.com',
36
+ subject: 'Hello from Unosend!',
37
+ html: '<h1>Welcome!</h1><p>Thanks for signing up.</p>'
38
+ )
39
+
40
+ puts "Email sent: #{email['id']}"
41
+ ```
42
+
43
+ ## Features
44
+
45
+ - 📧 **Emails** - Send transactional emails with HTML/text content
46
+ - 🌐 **Domains** - Manage and verify sending domains
47
+ - 👥 **Audiences** - Create and manage contact lists
48
+ - 📇 **Contacts** - Add, update, and remove contacts
49
+
50
+ ## API Reference
51
+
52
+ ### Emails
53
+
54
+ ```ruby
55
+ # Send an email
56
+ email = client.emails.send(
57
+ from: 'you@yourdomain.com',
58
+ to: ['user1@example.com', 'user2@example.com'],
59
+ subject: 'Hello!',
60
+ html: '<h1>Hello World</h1>',
61
+ text: 'Hello World', # Optional
62
+ reply_to: 'support@yourdomain.com',
63
+ cc: ['cc@example.com'],
64
+ bcc: ['bcc@example.com'],
65
+ headers: { 'X-Custom-Header' => 'value' },
66
+ tags: [{ name: 'campaign', value: 'welcome' }]
67
+ )
68
+
69
+ # Get email by ID
70
+ email = client.emails.get('email_id')
71
+
72
+ # List emails
73
+ emails = client.emails.list(limit: 10, offset: 0)
74
+ ```
75
+
76
+ ### Domains
77
+
78
+ ```ruby
79
+ # Add a domain
80
+ domain = client.domains.create('yourdomain.com')
81
+
82
+ # Verify domain DNS records
83
+ domain = client.domains.verify('domain_id')
84
+
85
+ # List domains
86
+ domains = client.domains.list
87
+
88
+ # Delete domain
89
+ client.domains.delete('domain_id')
90
+ ```
91
+
92
+ ### Audiences
93
+
94
+ ```ruby
95
+ # Create an audience
96
+ audience = client.audiences.create('Newsletter Subscribers')
97
+
98
+ # List audiences
99
+ audiences = client.audiences.list
100
+
101
+ # Get audience
102
+ audience = client.audiences.get('audience_id')
103
+
104
+ # Delete audience
105
+ client.audiences.delete('audience_id')
106
+ ```
107
+
108
+ ### Contacts
109
+
110
+ ```ruby
111
+ # Add a contact
112
+ contact = client.contacts.create(
113
+ audience_id: 'audience_id',
114
+ email: 'user@example.com',
115
+ first_name: 'John',
116
+ last_name: 'Doe'
117
+ )
118
+
119
+ # List contacts in an audience
120
+ contacts = client.contacts.list('audience_id')
121
+
122
+ # Update a contact
123
+ contact = client.contacts.update('contact_id',
124
+ first_name: 'Jane',
125
+ unsubscribed: false
126
+ )
127
+
128
+ # Delete a contact
129
+ client.contacts.delete('contact_id')
130
+ ```
131
+
132
+ ## Error Handling
133
+
134
+ ```ruby
135
+ begin
136
+ email = client.emails.send(...)
137
+ rescue Unosend::Error => e
138
+ puts "Error #{e.code}: #{e.message}"
139
+ end
140
+ ```
141
+
142
+ ## Configuration
143
+
144
+ ```ruby
145
+ # Custom base URL (for self-hosted instances)
146
+ client = Unosend::Client.new('un_your_api_key',
147
+ base_url: 'https://your-instance.com/api/v1'
148
+ )
149
+ ```
150
+
151
+ ## License
152
+
153
+ MIT
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unosend
4
+ class Audiences
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ # Create a new audience
10
+ #
11
+ # @param name [String] Audience name
12
+ # @return [Hash] The created audience
13
+ def create(name)
14
+ @client.request(:post, "/audiences", { name: name })
15
+ end
16
+
17
+ # Get an audience by ID
18
+ #
19
+ # @param id [String] Audience ID
20
+ # @return [Hash] The audience
21
+ def get(id)
22
+ @client.request(:get, "/audiences/#{id}")
23
+ end
24
+
25
+ # List all audiences
26
+ #
27
+ # @return [Array<Hash>] List of audiences
28
+ def list
29
+ @client.request(:get, "/audiences")
30
+ end
31
+
32
+ # Delete an audience
33
+ #
34
+ # @param id [String] Audience ID
35
+ # @return [Hash] Deletion confirmation
36
+ def delete(id)
37
+ @client.request(:delete, "/audiences/#{id}")
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "uri"
6
+
7
+ module Unosend
8
+ class Client
9
+ DEFAULT_BASE_URL = "https://www.unosend.co/api/v1"
10
+ USER_AGENT = "unosend-ruby/1.0.0"
11
+
12
+ attr_reader :emails, :domains, :audiences, :contacts
13
+
14
+ def initialize(api_key, base_url: DEFAULT_BASE_URL)
15
+ raise ArgumentError, "API key is required" if api_key.nil? || api_key.empty?
16
+
17
+ @api_key = api_key
18
+ @base_url = base_url
19
+
20
+ @emails = Emails.new(self)
21
+ @domains = Domains.new(self)
22
+ @audiences = Audiences.new(self)
23
+ @contacts = Contacts.new(self)
24
+ end
25
+
26
+ def request(method, path, body = nil)
27
+ uri = URI.parse("#{@base_url}#{path}")
28
+
29
+ http = Net::HTTP.new(uri.host, uri.port)
30
+ http.use_ssl = uri.scheme == "https"
31
+ http.read_timeout = 30
32
+ http.open_timeout = 10
33
+
34
+ request = build_request(method, uri, body)
35
+
36
+ response = http.request(request)
37
+ parse_response(response)
38
+ end
39
+
40
+ private
41
+
42
+ def build_request(method, uri, body)
43
+ request = case method.to_s.upcase
44
+ when "GET"
45
+ Net::HTTP::Get.new(uri)
46
+ when "POST"
47
+ Net::HTTP::Post.new(uri)
48
+ when "PUT"
49
+ Net::HTTP::Put.new(uri)
50
+ when "PATCH"
51
+ Net::HTTP::Patch.new(uri)
52
+ when "DELETE"
53
+ Net::HTTP::Delete.new(uri)
54
+ else
55
+ raise ArgumentError, "Unsupported HTTP method: #{method}"
56
+ end
57
+
58
+ request["Authorization"] = "Bearer #{@api_key}"
59
+ request["Content-Type"] = "application/json"
60
+ request["User-Agent"] = USER_AGENT
61
+
62
+ request.body = body.to_json if body
63
+
64
+ request
65
+ end
66
+
67
+ def parse_response(response)
68
+ body = response.body ? JSON.parse(response.body) : {}
69
+
70
+ unless response.is_a?(Net::HTTPSuccess)
71
+ error = body["error"] || {}
72
+ raise Error.new(
73
+ error["message"] || "Unknown error",
74
+ code: error["code"] || response.code.to_i,
75
+ status_code: response.code.to_i
76
+ )
77
+ end
78
+
79
+ body["data"] || body
80
+ rescue JSON::ParserError
81
+ raise Error.new("Invalid JSON response", code: 0)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unosend
4
+ class Contacts
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ # Create a new contact
10
+ #
11
+ # @param audience_id [String] Audience ID
12
+ # @param email [String] Contact email
13
+ # @param first_name [String] First name (optional)
14
+ # @param last_name [String] Last name (optional)
15
+ # @return [Hash] The created contact
16
+ def create(audience_id:, email:, first_name: nil, last_name: nil)
17
+ payload = {
18
+ audienceId: audience_id,
19
+ email: email
20
+ }
21
+
22
+ payload[:firstName] = first_name if first_name
23
+ payload[:lastName] = last_name if last_name
24
+
25
+ @client.request(:post, "/contacts", payload)
26
+ end
27
+
28
+ # Get a contact by ID
29
+ #
30
+ # @param id [String] Contact ID
31
+ # @return [Hash] The contact
32
+ def get(id)
33
+ @client.request(:get, "/contacts/#{id}")
34
+ end
35
+
36
+ # List contacts in an audience
37
+ #
38
+ # @param audience_id [String] Audience ID
39
+ # @return [Array<Hash>] List of contacts
40
+ def list(audience_id)
41
+ @client.request(:get, "/contacts?audienceId=#{audience_id}")
42
+ end
43
+
44
+ # Update a contact
45
+ #
46
+ # @param id [String] Contact ID
47
+ # @param first_name [String] First name (optional)
48
+ # @param last_name [String] Last name (optional)
49
+ # @param unsubscribed [Boolean] Unsubscribed status (optional)
50
+ # @return [Hash] The updated contact
51
+ def update(id, first_name: nil, last_name: nil, unsubscribed: nil)
52
+ payload = {}
53
+ payload[:firstName] = first_name unless first_name.nil?
54
+ payload[:lastName] = last_name unless last_name.nil?
55
+ payload[:unsubscribed] = unsubscribed unless unsubscribed.nil?
56
+
57
+ @client.request(:patch, "/contacts/#{id}", payload)
58
+ end
59
+
60
+ # Delete a contact
61
+ #
62
+ # @param id [String] Contact ID
63
+ # @return [Hash] Deletion confirmation
64
+ def delete(id)
65
+ @client.request(:delete, "/contacts/#{id}")
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unosend
4
+ class Domains
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ # Create a new domain
10
+ #
11
+ # @param name [String] Domain name
12
+ # @return [Hash] The created domain
13
+ def create(name)
14
+ @client.request(:post, "/domains", { name: name })
15
+ end
16
+
17
+ # Get a domain by ID
18
+ #
19
+ # @param id [String] Domain ID
20
+ # @return [Hash] The domain
21
+ def get(id)
22
+ @client.request(:get, "/domains/#{id}")
23
+ end
24
+
25
+ # List all domains
26
+ #
27
+ # @return [Array<Hash>] List of domains
28
+ def list
29
+ @client.request(:get, "/domains")
30
+ end
31
+
32
+ # Verify a domain
33
+ #
34
+ # @param id [String] Domain ID
35
+ # @return [Hash] The verified domain
36
+ def verify(id)
37
+ @client.request(:post, "/domains/#{id}/verify")
38
+ end
39
+
40
+ # Delete a domain
41
+ #
42
+ # @param id [String] Domain ID
43
+ # @return [Hash] Deletion confirmation
44
+ def delete(id)
45
+ @client.request(:delete, "/domains/#{id}")
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unosend
4
+ class Emails
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ # Send an email
10
+ #
11
+ # @param from [String] Sender email address
12
+ # @param to [String, Array<String>] Recipient email address(es)
13
+ # @param subject [String] Email subject
14
+ # @param html [String] HTML content (optional)
15
+ # @param text [String] Plain text content (optional)
16
+ # @param reply_to [String] Reply-to address (optional)
17
+ # @param cc [String, Array<String>] CC recipients (optional)
18
+ # @param bcc [String, Array<String>] BCC recipients (optional)
19
+ # @param headers [Hash] Custom headers (optional)
20
+ # @param tags [Array<Hash>] Tags (optional)
21
+ # @param priority [String] Priority: 'high', 'normal', or 'low' (optional)
22
+ # @param template_id [String] Template UUID (optional)
23
+ # @param template_data [Hash] Template variables (optional)
24
+ # @param scheduled_for [String] ISO 8601 datetime (optional)
25
+ # @return [Hash] The sent email
26
+ def send(from:, to:, subject:, html: nil, text: nil, reply_to: nil, cc: nil, bcc: nil, headers: nil, tags: nil, priority: nil, template_id: nil, template_data: nil, scheduled_for: nil)
27
+ payload = {
28
+ from: from,
29
+ to: Array(to),
30
+ subject: subject
31
+ }
32
+
33
+ payload[:html] = html if html
34
+ payload[:text] = text if text
35
+ payload[:reply_to] = reply_to if reply_to
36
+ payload[:cc] = Array(cc) if cc
37
+ payload[:bcc] = Array(bcc) if bcc
38
+ payload[:headers] = headers if headers
39
+ payload[:tags] = tags if tags
40
+ payload[:priority] = priority if priority
41
+ payload[:template_id] = template_id if template_id
42
+ payload[:template_data] = template_data if template_data
43
+ payload[:scheduled_for] = scheduled_for if scheduled_for
44
+
45
+ @client.request(:post, "/emails", payload)
46
+ end
47
+
48
+ # Get an email by ID
49
+ #
50
+ # @param id [String] Email ID
51
+ # @return [Hash] The email
52
+ def get(id)
53
+ @client.request(:get, "/emails/#{id}")
54
+ end
55
+
56
+ # List emails
57
+ #
58
+ # @param limit [Integer] Maximum number of results (optional)
59
+ # @param offset [Integer] Offset for pagination (optional)
60
+ # @return [Array<Hash>] List of emails
61
+ def list(limit: nil, offset: nil)
62
+ path = "/emails"
63
+ params = []
64
+ params << "limit=#{limit}" if limit
65
+ params << "offset=#{offset}" if offset
66
+ path += "?#{params.join("&")}" unless params.empty?
67
+
68
+ @client.request(:get, path)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unosend
4
+ VERSION = "1.0.0"
5
+ end
data/lib/unosend.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "unosend/version"
4
+ require_relative "unosend/client"
5
+ require_relative "unosend/emails"
6
+ require_relative "unosend/domains"
7
+ require_relative "unosend/audiences"
8
+ require_relative "unosend/contacts"
9
+
10
+ module Unosend
11
+ class Error < StandardError
12
+ attr_reader :code, :status_code
13
+
14
+ def initialize(message, code: nil, status_code: nil)
15
+ @code = code
16
+ @status_code = status_code
17
+ super(message)
18
+ end
19
+ end
20
+ end
data/test.rb ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path('lib', __dir__))
4
+
5
+ require 'unosend'
6
+
7
+ client = Unosend::Client.new('un_YUp9yHlMtrGvuJqmH6kU_7eXJaU3gPcW')
8
+
9
+ puts "Testing Ruby SDK..."
10
+ puts ""
11
+
12
+ puts "Sending email..."
13
+ begin
14
+ email = client.emails.send(
15
+ from: 'hello@unosend.co',
16
+ to: 'bittucreator@gmail.com',
17
+ subject: 'Test from Ruby SDK',
18
+ html: '<h1>Hello from Ruby!</h1><p>This email was sent using the official Unosend Ruby SDK.</p>'
19
+ )
20
+ puts "Success! Email ID: #{email['id']}"
21
+ rescue Unosend::Error => e
22
+ puts "Error #{e.code}: #{e.message}"
23
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unosend
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Unosend
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-12-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Send emails with Unosend's powerful API. Features include transactional
14
+ emails, audience management, and domain verification.
15
+ email:
16
+ - support@unosend.co
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - README.md
22
+ - lib/unosend.rb
23
+ - lib/unosend/audiences.rb
24
+ - lib/unosend/client.rb
25
+ - lib/unosend/contacts.rb
26
+ - lib/unosend/domains.rb
27
+ - lib/unosend/emails.rb
28
+ - lib/unosend/version.rb
29
+ - test.rb
30
+ homepage: https://unosend.co
31
+ licenses:
32
+ - MIT
33
+ metadata:
34
+ homepage_uri: https://unosend.co
35
+ source_code_uri: https://github.com/unosend/unosend-ruby
36
+ changelog_uri: https://github.com/unosend/unosend-ruby/blob/main/CHANGELOG.md
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 2.7.0
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubygems_version: 3.0.3.1
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Official Ruby SDK for Unosend - Email API Service
56
+ test_files: []