emailfuse 0.1.4 → 0.2.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/CHANGELOG.md +131 -0
- data/README.md +90 -9
- data/lib/email_fuse/batch.rb +36 -0
- data/lib/email_fuse/client.rb +19 -0
- data/lib/email_fuse/emails/attachments.rb +67 -0
- data/lib/email_fuse/emails/receiving/attachments.rb +69 -0
- data/lib/email_fuse/emails/receiving.rb +43 -0
- data/lib/email_fuse/emails.rb +55 -0
- data/lib/email_fuse/errors.rb +52 -0
- data/lib/email_fuse/mailer.rb +257 -0
- data/lib/email_fuse/pagination_helper.rb +30 -0
- data/lib/email_fuse/railtie.rb +14 -0
- data/lib/email_fuse/request.rb +121 -0
- data/lib/email_fuse/response.rb +141 -0
- data/lib/email_fuse/version.rb +5 -0
- data/lib/email_fuse/webhooks.rb +239 -0
- data/lib/email_fuse.rb +43 -0
- data/lib/emailfuse.rb +2 -31
- metadata +31 -45
- data/Rakefile +0 -10
- data/lib/emailfuse/client.rb +0 -69
- data/lib/emailfuse/collection.rb +0 -27
- data/lib/emailfuse/configuration.rb +0 -10
- data/lib/emailfuse/deliverer.rb +0 -72
- data/lib/emailfuse/error.rb +0 -4
- data/lib/emailfuse/models/email.rb +0 -21
- data/lib/emailfuse/object.rb +0 -19
- data/lib/emailfuse/railtie.rb +0 -12
- data/lib/emailfuse/version.rb +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed5308d363064b9bea74f6d008a55bde447dc2f956689a2d357e8ce8467775b9
|
|
4
|
+
data.tar.gz: 259675d6b858aba7da91e34b31e7a199ab5f98b70b81bbc0c64b8e72c959c01f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eb5deeb16c7d71d1873557cbbdace95c73e3d3c913f4a157f8c55345ce3c06636d16abbbb69d5a268b461b4dbec81faa15d435db1a6e77f311f60183b4127027
|
|
7
|
+
data.tar.gz: cd86a4342f1994e0462f90537de60d36e29baea5b737fa383bd6d5cdb8bde5e943dc4910a3fd3332c4b50eeeba0c9d8132344c641bcb773373f8f319928c0bcf
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2025-10-31
|
|
9
|
+
|
|
10
|
+
### Overview
|
|
11
|
+
|
|
12
|
+
This major release introduces breaking changes to the Contacts API and deprecates the Audiences API in favor of Segments. **If you only use the SDK for sending emails or the Audiences API, you can upgrade to v1.0.0 without any code changes.** The breaking changes are limited to the Contacts API only.
|
|
13
|
+
|
|
14
|
+
### ⚠️ BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
#### Contacts API Changes
|
|
17
|
+
|
|
18
|
+
- ⚠️ **Change `Contacts.create` to accept hash parameter with optional `audience_id`** - Previously required `audience_id` in params, now it's optional. Supports global contacts.
|
|
19
|
+
- ⚠️ **Change `Contacts.get` from `get(audience_id, id)` to `get(params)`** - Now accepts a hash with optional `audience_id` and required `id` or `email`. Raises `ArgumentError: "Missing \`id\` or \`email\` field"` when neither is provided.
|
|
20
|
+
- ⚠️ **Change `Contacts.list` from `list(audience_id, params = {})` to `list(params = {})`** - Now accepts a hash with optional `audience_id` and pagination params
|
|
21
|
+
- ⚠️ **Change `Contacts.remove` from `remove(audience_id, contact_id)` to `remove(params)`** - Now accepts a hash with optional `audience_id` and required `id` or `email`. Raises `ArgumentError: "Missing \`id\` or \`email\` field"` when neither is provided.
|
|
22
|
+
- ⚠️ **Change `Contacts.update` error message** - Error changed from `"id or email is required"` to `"Missing \`id\` or \`email\` field"` to match Node.js SDK format
|
|
23
|
+
- ⚠️ **Change `Contacts.update` to accept optional `audience_id`** - Previously required `audience_id` in params, now it's optional
|
|
24
|
+
|
|
25
|
+
**Before (v0.x):**
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# Methods used positional arguments and required audience_id
|
|
29
|
+
Resend::Contacts.create(audience_id: "aud_123", email: "user@example.com", first_name: "John")
|
|
30
|
+
contact = Resend::Contacts.get("aud_123", "contact_123")
|
|
31
|
+
contacts = Resend::Contacts.list("aud_123")
|
|
32
|
+
contacts = Resend::Contacts.list("aud_123", limit: 10)
|
|
33
|
+
Resend::Contacts.update(audience_id: "aud_123", id: "contact_123", first_name: "Jane")
|
|
34
|
+
Resend::Contacts.remove("aud_123", "contact_123")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**After (v1.0.0):**
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
# Methods use hash parameters and support optional audience_id
|
|
41
|
+
# Global contacts (no audience_id)
|
|
42
|
+
Resend::Contacts.create(email: "user@example.com", first_name: "John")
|
|
43
|
+
contact = Resend::Contacts.get(id: "contact_123")
|
|
44
|
+
contact = Resend::Contacts.get(email: "user@example.com")
|
|
45
|
+
contacts = Resend::Contacts.list
|
|
46
|
+
contacts = Resend::Contacts.list(limit: 10)
|
|
47
|
+
Resend::Contacts.update(id: "contact_123", first_name: "Jane")
|
|
48
|
+
Resend::Contacts.remove(id: "contact_123")
|
|
49
|
+
|
|
50
|
+
# Audience-scoped contacts (with audience_id)
|
|
51
|
+
Resend::Contacts.create(audience_id: "aud_123", email: "user@example.com", first_name: "John")
|
|
52
|
+
contact = Resend::Contacts.get(audience_id: "aud_123", id: "contact_123")
|
|
53
|
+
contacts = Resend::Contacts.list(audience_id: "aud_123", limit: 10)
|
|
54
|
+
Resend::Contacts.update(audience_id: "aud_123", id: "contact_123", first_name: "Jane")
|
|
55
|
+
Resend::Contacts.remove(audience_id: "aud_123", id: "contact_123")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Audiences API Deprecated
|
|
59
|
+
|
|
60
|
+
- ⚠️ **Deprecate `Resend::Audiences` in favor of `Resend::Segments`** - The Audiences module has been replaced with Segments. A backward-compatible alias `Audiences = Segments` has been added, so existing code will continue to work.
|
|
61
|
+
|
|
62
|
+
**Migration (Recommended):**
|
|
63
|
+
|
|
64
|
+
Update your code to use `Segments` instead of `Audiences`:
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
# Before (still works but deprecated)
|
|
68
|
+
Resend::Audiences.create(name: "My Audience")
|
|
69
|
+
Resend::Audiences.get("audience_123")
|
|
70
|
+
Resend::Audiences.list
|
|
71
|
+
Resend::Audiences.remove("audience_123")
|
|
72
|
+
|
|
73
|
+
# After (recommended)
|
|
74
|
+
Resend::Segments.create(name: "My Segment")
|
|
75
|
+
Resend::Segments.get("segment_123")
|
|
76
|
+
Resend::Segments.list
|
|
77
|
+
Resend::Segments.remove("segment_123")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Note:** The `Audiences` alias is deprecated and may be removed in a future major version. Please migrate to `Segments`.
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
|
|
84
|
+
#### New API Modules
|
|
85
|
+
|
|
86
|
+
- Add `Resend::Templates` API for managing email templates
|
|
87
|
+
- `Templates.create` - Create a new template
|
|
88
|
+
- `Templates.get` - Retrieve a template by ID
|
|
89
|
+
- `Templates.update` - Update an existing template
|
|
90
|
+
- `Templates.publish` - Publish a template
|
|
91
|
+
- `Templates.duplicate` - Duplicate an existing template
|
|
92
|
+
- `Templates.list` - List all templates with pagination
|
|
93
|
+
- `Templates.remove` - Delete a template
|
|
94
|
+
- Add `Resend::Topics` API for managing topics
|
|
95
|
+
- `Topics.create` - Create a new topic
|
|
96
|
+
- `Topics.get` - Retrieve a topic by ID
|
|
97
|
+
- `Topics.update` - Update a topic
|
|
98
|
+
- `Topics.list` - List all topics with pagination
|
|
99
|
+
- `Topics.remove` - Delete a topic
|
|
100
|
+
- Add `Resend::Segments` API for managing segments (replacement for Audiences)
|
|
101
|
+
- `Segments.create` - Create a new segment
|
|
102
|
+
- `Segments.get` - Retrieve a segment by ID
|
|
103
|
+
- `Segments.list` - List all segments
|
|
104
|
+
- `Segments.remove` - Delete a segment
|
|
105
|
+
- Add `Resend::ContactProperties` API for managing custom contact properties
|
|
106
|
+
- `ContactProperties.update` - Update contact properties (validates and raises `ArgumentError: "Missing \`id\` field"` when id is not provided)
|
|
107
|
+
- `ContactProperties.get` - Retrieve contact properties by ID
|
|
108
|
+
- Add `Resend::Contacts::Segments` API for managing contact-segment relationships
|
|
109
|
+
- `Contacts::Segments.list` - List all segments for a contact
|
|
110
|
+
- `Contacts::Segments.add` - Add a contact to a segment
|
|
111
|
+
- `Contacts::Segments.remove` - Remove a contact from a segment
|
|
112
|
+
- Add `Resend::Contacts::Topics` API for managing contact topic subscriptions
|
|
113
|
+
- `Contacts::Topics.list` - List topic subscriptions for a contact
|
|
114
|
+
- `Contacts::Topics.update` - Update topic subscriptions (opt-in/opt-out) for a contact
|
|
115
|
+
|
|
116
|
+
#### Contacts API Enhancements
|
|
117
|
+
|
|
118
|
+
- Add support for `email` parameter in `Contacts.get` and `Contacts.remove` methods (can now use email instead of ID)
|
|
119
|
+
- Add `audience_id` support in Contacts API methods for scoped operations
|
|
120
|
+
- Add support for global contacts (contacts not scoped to a specific audience/segment)
|
|
121
|
+
- Add validation error messages matching Node.js SDK format with backticks around field names
|
|
122
|
+
|
|
123
|
+
#### Broadcasts API Updates
|
|
124
|
+
|
|
125
|
+
- Add deprecation warnings for `audience_id` in `Broadcasts.create` and `Broadcasts.update` (use `segment_id` instead)
|
|
126
|
+
|
|
127
|
+
### Removed
|
|
128
|
+
|
|
129
|
+
- Remove deprecated `send_email` method from `Resend::Emails` module (use `Resend::Emails.send` instead)
|
|
130
|
+
|
|
131
|
+
[1.0.0]: https://github.com/resend/resend-ruby/compare/v0.26.0...v1.0.0
|
data/README.md
CHANGED
|
@@ -1,22 +1,103 @@
|
|
|
1
|
-
#
|
|
1
|
+
# EmailFuse Ruby and Rails SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
---
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
To install EmailFuse Ruby and Rails SDK, simply execute the following command in a terminal:
|
|
8
|
+
|
|
9
|
+
Via RubyGems:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
gem install emailfuse
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Via Gemfile:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
gem 'emailfuse'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
8
22
|
|
|
9
23
|
```ruby
|
|
10
|
-
|
|
24
|
+
require "emailfuse"
|
|
25
|
+
EmailFuse.api_key = ENV["EMAILFUSE_API_KEY"]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
or
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
require "emailfuse"
|
|
32
|
+
EmailFuse.configure do |config|
|
|
33
|
+
config.api_key = ENV["EMAILFUSE_API_KEY"]
|
|
34
|
+
end
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
```rb
|
|
40
|
+
require "emailfuse"
|
|
41
|
+
|
|
42
|
+
EmailFuse.api_key = ENV["EMAILFUSE_API_KEY"]
|
|
43
|
+
|
|
44
|
+
params = {
|
|
45
|
+
"from": "onboarding@resend.dev",
|
|
46
|
+
"to": ["delivered@resend.dev", "your@email.com"],
|
|
47
|
+
"html": "<h1>Hello World</h1>",
|
|
48
|
+
"subject": "Hey"
|
|
49
|
+
}
|
|
50
|
+
r = EmailFuse::Emails.send(params)
|
|
51
|
+
puts r
|
|
11
52
|
```
|
|
12
53
|
|
|
13
|
-
|
|
54
|
+
# Rails and ActionMailer support
|
|
14
55
|
|
|
15
|
-
|
|
56
|
+
This gem can be used as an ActionMailer delivery method, add this to your `config/environments/environment.rb` file.
|
|
16
57
|
|
|
17
58
|
```ruby
|
|
18
59
|
config.action_mailer.delivery_method = :emailfuse
|
|
19
|
-
|
|
20
|
-
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Configuration Options
|
|
63
|
+
|
|
64
|
+
You can configure the API key and host in two ways:
|
|
65
|
+
|
|
66
|
+
#### Option 1: Global Configuration (Initializer)
|
|
67
|
+
|
|
68
|
+
Create or update your mailer initializer file:
|
|
69
|
+
|
|
70
|
+
```rb
|
|
71
|
+
# /config/initializers/emailfuse.rb
|
|
72
|
+
EmailFuse.configure do |config|
|
|
73
|
+
config.api_key = ENV["EMAILFUSE_API_KEY"]
|
|
74
|
+
config.base_url = "https://api.emailfuse.net" # optional, defaults to https://api.emailfuse.net
|
|
21
75
|
end
|
|
22
76
|
```
|
|
77
|
+
|
|
78
|
+
#### Option 2: Rails Mailer Settings
|
|
79
|
+
|
|
80
|
+
Configure directly in your environment file:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
# config/environments/production.rb
|
|
84
|
+
config.action_mailer.delivery_method = :emailfuse
|
|
85
|
+
config.action_mailer.emailfuse_settings = {
|
|
86
|
+
api_key: ENV["EMAILFUSE_API_KEY"],
|
|
87
|
+
host: "https://api.emailfuse.net" # optional
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Settings configured via `emailfuse_settings` take precedence over the global configuration, allowing you to use different credentials per environment.
|
|
92
|
+
|
|
93
|
+
### Sending Emails
|
|
94
|
+
|
|
95
|
+
After configuration, you can use `deliver_now!`:
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
mailer = EmailMailer.email(self)
|
|
99
|
+
response = mailer.deliver_now!
|
|
100
|
+
|
|
101
|
+
puts response[:id]
|
|
102
|
+
# => "b8f94710-0d84-429c-925a-22d3d8f86916"
|
|
103
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EmailFuse
|
|
4
|
+
# Module responsible for wrapping Batch email sending API
|
|
5
|
+
module Batch
|
|
6
|
+
class << self
|
|
7
|
+
# Send a batch of emails
|
|
8
|
+
#
|
|
9
|
+
# @param params [Array<Hash>] Array of email parameters (max 100 emails)
|
|
10
|
+
# @param options [Hash] Additional options for the request
|
|
11
|
+
# @option options [String] :idempotency_key Optional idempotency key
|
|
12
|
+
# @option options [String] :batch_validation Batch validation mode: "strict" (default) or "permissive"
|
|
13
|
+
# - "strict": Entire batch fails if any email is invalid
|
|
14
|
+
# - "permissive": Sends valid emails and returns errors for invalid ones
|
|
15
|
+
#
|
|
16
|
+
# @return [Hash] Response with :data array and optional :errors array (in permissive mode)
|
|
17
|
+
#
|
|
18
|
+
# @example Send batch with strict validation (default)
|
|
19
|
+
# EmailFuse::Batch.send([
|
|
20
|
+
# { from: "sender@example.com", to: ["recipient@example.com"], subject: "Hello", html: "<p>Hi</p>" }
|
|
21
|
+
# ])
|
|
22
|
+
#
|
|
23
|
+
# @example Send batch with permissive validation
|
|
24
|
+
# response = EmailFuse::Batch.send(emails, options: { batch_validation: "permissive" })
|
|
25
|
+
# # response[:data] contains successful email IDs
|
|
26
|
+
# # response[:errors] contains validation errors with index and message
|
|
27
|
+
#
|
|
28
|
+
# https://resend.com/docs/api-reference/emails/send-batch-emails
|
|
29
|
+
def send(params = [], options: {})
|
|
30
|
+
path = "emails/batch"
|
|
31
|
+
|
|
32
|
+
EmailFuse::Request.new(path, params, "post", options: options).perform
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# backwards compatibility
|
|
4
|
+
require "email_fuse/emails"
|
|
5
|
+
|
|
6
|
+
module EmailFuse
|
|
7
|
+
# Client class.
|
|
8
|
+
class Client
|
|
9
|
+
include EmailFuse::Emails
|
|
10
|
+
|
|
11
|
+
attr_reader :api_key
|
|
12
|
+
|
|
13
|
+
def initialize(api_key)
|
|
14
|
+
raise ArgumentError, "API Key is not a string" unless api_key.is_a?(String)
|
|
15
|
+
|
|
16
|
+
@api_key = api_key
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EmailFuse
|
|
4
|
+
module Emails
|
|
5
|
+
# Module for sent email attachments API operations
|
|
6
|
+
module Attachments
|
|
7
|
+
class << self
|
|
8
|
+
# Retrieve a single attachment from a sent email
|
|
9
|
+
#
|
|
10
|
+
# @param params [Hash] Parameters for retrieving the attachment
|
|
11
|
+
# @option params [String] :id The attachment ID (required)
|
|
12
|
+
# @option params [String] :email_id The email ID (required)
|
|
13
|
+
# @return [Hash] The attachment object
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# EmailFuse::Emails::Attachments.get(
|
|
17
|
+
# id: "2a0c9ce0-3112-4728-976e-47ddcd16a318",
|
|
18
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
|
|
19
|
+
# )
|
|
20
|
+
def get(params = {})
|
|
21
|
+
attachment_id = params[:id]
|
|
22
|
+
email_id = params[:email_id]
|
|
23
|
+
|
|
24
|
+
path = "emails/#{email_id}/attachments/#{attachment_id}"
|
|
25
|
+
EmailFuse::Request.new(path, {}, "get").perform
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# List attachments from a sent email with optional pagination
|
|
29
|
+
#
|
|
30
|
+
# @param params [Hash] Parameters for listing attachments
|
|
31
|
+
# @option params [String] :email_id The email ID (required)
|
|
32
|
+
# @option params [Integer] :limit Maximum number of attachments to return (1-100)
|
|
33
|
+
# @option params [String] :after Cursor for pagination (newer attachments)
|
|
34
|
+
# @option params [String] :before Cursor for pagination (older attachments)
|
|
35
|
+
# @return [Hash] List of attachments with pagination info
|
|
36
|
+
#
|
|
37
|
+
# @example List all attachments
|
|
38
|
+
# EmailFuse::Emails::Attachments.list(
|
|
39
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
|
|
40
|
+
# )
|
|
41
|
+
#
|
|
42
|
+
# @example List with custom limit
|
|
43
|
+
# EmailFuse::Emails::Attachments.list(
|
|
44
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
|
|
45
|
+
# limit: 50
|
|
46
|
+
# )
|
|
47
|
+
#
|
|
48
|
+
# @example List with pagination
|
|
49
|
+
# EmailFuse::Emails::Attachments.list(
|
|
50
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
|
|
51
|
+
# limit: 20,
|
|
52
|
+
# after: "attachment_id_123"
|
|
53
|
+
# )
|
|
54
|
+
def list(params = {})
|
|
55
|
+
email_id = params[:email_id]
|
|
56
|
+
base_path = "emails/#{email_id}/attachments"
|
|
57
|
+
|
|
58
|
+
# Extract pagination parameters
|
|
59
|
+
pagination_params = params.slice(:limit, :after, :before)
|
|
60
|
+
|
|
61
|
+
path = EmailFuse::PaginationHelper.build_paginated_path(base_path, pagination_params)
|
|
62
|
+
EmailFuse::Request.new(path, {}, "get").perform
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EmailFuse
|
|
4
|
+
module Emails
|
|
5
|
+
module Receiving
|
|
6
|
+
# Module for received email attachments API operations
|
|
7
|
+
module Attachments
|
|
8
|
+
class << self
|
|
9
|
+
# Retrieve a single attachment from a received email
|
|
10
|
+
#
|
|
11
|
+
# @param params [Hash] Parameters for retrieving the attachment
|
|
12
|
+
# @option params [String] :id The attachment ID (required)
|
|
13
|
+
# @option params [String] :email_id The email ID (required)
|
|
14
|
+
# @return [Hash] The attachment object
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# EmailFuse::Emails::Receiving::Attachments.get(
|
|
18
|
+
# id: "2a0c9ce0-3112-4728-976e-47ddcd16a318",
|
|
19
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
|
|
20
|
+
# )
|
|
21
|
+
def get(params = {})
|
|
22
|
+
attachment_id = params[:id]
|
|
23
|
+
email_id = params[:email_id]
|
|
24
|
+
|
|
25
|
+
path = "emails/receiving/#{email_id}/attachments/#{attachment_id}"
|
|
26
|
+
EmailFuse::Request.new(path, {}, "get").perform
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# List attachments from a received email with optional pagination
|
|
30
|
+
#
|
|
31
|
+
# @param params [Hash] Parameters for listing attachments
|
|
32
|
+
# @option params [String] :email_id The email ID (required)
|
|
33
|
+
# @option params [Integer] :limit Maximum number of attachments to return (1-100)
|
|
34
|
+
# @option params [String] :after Cursor for pagination (newer attachments)
|
|
35
|
+
# @option params [String] :before Cursor for pagination (older attachments)
|
|
36
|
+
# @return [Hash] List of attachments with pagination info
|
|
37
|
+
#
|
|
38
|
+
# @example List all attachments
|
|
39
|
+
# EmailFuse::Emails::Receiving::Attachments.list(
|
|
40
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
|
|
41
|
+
# )
|
|
42
|
+
#
|
|
43
|
+
# @example List with custom limit
|
|
44
|
+
# EmailFuse::Emails::Receiving::Attachments.list(
|
|
45
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
|
|
46
|
+
# limit: 50
|
|
47
|
+
# )
|
|
48
|
+
#
|
|
49
|
+
# @example List with pagination
|
|
50
|
+
# EmailFuse::Emails::Receiving::Attachments.list(
|
|
51
|
+
# email_id: "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
|
|
52
|
+
# limit: 20,
|
|
53
|
+
# after: "attachment_id_123"
|
|
54
|
+
# )
|
|
55
|
+
def list(params = {})
|
|
56
|
+
email_id = params[:email_id]
|
|
57
|
+
base_path = "emails/receiving/#{email_id}/attachments"
|
|
58
|
+
|
|
59
|
+
# Extract pagination parameters
|
|
60
|
+
pagination_params = params.slice(:limit, :after, :before)
|
|
61
|
+
|
|
62
|
+
path = EmailFuse::PaginationHelper.build_paginated_path(base_path, pagination_params)
|
|
63
|
+
EmailFuse::Request.new(path, {}, "get").perform
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EmailFuse
|
|
4
|
+
module Emails
|
|
5
|
+
# Module for receiving emails API operations
|
|
6
|
+
module Receiving
|
|
7
|
+
class << self
|
|
8
|
+
# Retrieve a single received email
|
|
9
|
+
#
|
|
10
|
+
# @param email_id [String] The ID of the received email
|
|
11
|
+
# @return [Hash] The received email object
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# EmailFuse::Emails::Receiving.get("4ef9a417-02e9-4d39-ad75-9611e0fcc33c")
|
|
15
|
+
def get(email_id = "")
|
|
16
|
+
path = "emails/receiving/#{email_id}"
|
|
17
|
+
EmailFuse::Request.new(path, {}, "get").perform
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# List received emails with optional pagination
|
|
21
|
+
#
|
|
22
|
+
# @param params [Hash] Optional parameters for pagination
|
|
23
|
+
# @option params [Integer] :limit Maximum number of emails to return (1-100)
|
|
24
|
+
# @option params [String] :after Cursor for pagination (newer emails)
|
|
25
|
+
# @option params [String] :before Cursor for pagination (older emails)
|
|
26
|
+
# @return [Hash] List of received emails with pagination info
|
|
27
|
+
#
|
|
28
|
+
# @example List all received emails
|
|
29
|
+
# EmailFuse::Emails::Receiving.list
|
|
30
|
+
#
|
|
31
|
+
# @example List with custom limit
|
|
32
|
+
# EmailFuse::Emails::Receiving.list(limit: 50)
|
|
33
|
+
#
|
|
34
|
+
# @example List with pagination
|
|
35
|
+
# EmailFuse::Emails::Receiving.list(limit: 20, after: "email_id_123")
|
|
36
|
+
def list(params = {})
|
|
37
|
+
path = EmailFuse::PaginationHelper.build_paginated_path("emails/receiving", params)
|
|
38
|
+
EmailFuse::Request.new(path, {}, "get").perform
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EmailFuse
|
|
4
|
+
# Module responsible for wrapping email sending API
|
|
5
|
+
module Emails
|
|
6
|
+
class << self
|
|
7
|
+
# Sends or schedules an email.
|
|
8
|
+
# see more: https://resend.com/docs/api-reference/emails/send-email
|
|
9
|
+
def send(params, options: {})
|
|
10
|
+
path = "emails"
|
|
11
|
+
EmailFuse::Request.new(path, params, "post", options: options).perform
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Retrieve a single email.
|
|
15
|
+
# see more: https://resend.com/docs/api-reference/emails/retrieve-email
|
|
16
|
+
def get(email_id = "")
|
|
17
|
+
path = "emails/#{email_id}"
|
|
18
|
+
EmailFuse::Request.new(path, {}, "get").perform
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Update a scheduled email.
|
|
22
|
+
# see more: https://resend.com/docs/api-reference/emails/update-email
|
|
23
|
+
def update(params)
|
|
24
|
+
path = "emails/#{params[:email_id]}"
|
|
25
|
+
EmailFuse::Request.new(path, params, "patch").perform
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Cancel a scheduled email.
|
|
29
|
+
# see more: https://resend.com/docs/api-reference/emails/cancel-email
|
|
30
|
+
def cancel(email_id = "")
|
|
31
|
+
path = "emails/#{email_id}/cancel"
|
|
32
|
+
EmailFuse::Request.new(path, {}, "post").perform
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# List emails with optional pagination.
|
|
36
|
+
# see more: https://resend.com/docs/api-reference/emails/list-emails
|
|
37
|
+
#
|
|
38
|
+
# @param options [Hash] Optional parameters for pagination
|
|
39
|
+
# @option options [Integer] :limit Maximum number of emails to return (1-100, default 20)
|
|
40
|
+
# @option options [String] :after Cursor for pagination (newer emails)
|
|
41
|
+
# @option options [String] :before Cursor for pagination (older emails)
|
|
42
|
+
def list(options = {})
|
|
43
|
+
path = "emails"
|
|
44
|
+
|
|
45
|
+
# Build query parameters, filtering out nil values
|
|
46
|
+
query_params = {}
|
|
47
|
+
query_params[:limit] = options[:limit] if options[:limit]
|
|
48
|
+
query_params[:after] = options[:after] if options[:after]
|
|
49
|
+
query_params[:before] = options[:before] if options[:before]
|
|
50
|
+
|
|
51
|
+
EmailFuse::Request.new(path, query_params, "get").perform
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EmailFuse
|
|
4
|
+
# Errors wrapper class
|
|
5
|
+
# For more info: https://resend.com/docs/api-reference/error-codes
|
|
6
|
+
class Error < StandardError
|
|
7
|
+
# 4xx HTTP status code
|
|
8
|
+
ClientError = Class.new(self)
|
|
9
|
+
|
|
10
|
+
# 5xx HTTP status code
|
|
11
|
+
ServerError = Class.new(self)
|
|
12
|
+
|
|
13
|
+
# code 500
|
|
14
|
+
InternalServerError = Class.new(ServerError)
|
|
15
|
+
|
|
16
|
+
# code 422
|
|
17
|
+
InvalidRequestError = Class.new(ServerError)
|
|
18
|
+
|
|
19
|
+
# code 429
|
|
20
|
+
class RateLimitExceededError < ServerError
|
|
21
|
+
attr_reader :rate_limit_limit, :rate_limit_remaining, :rate_limit_reset, :retry_after
|
|
22
|
+
|
|
23
|
+
def initialize(msg, code = nil, headers = {})
|
|
24
|
+
super(msg, code, headers)
|
|
25
|
+
@rate_limit_limit = headers["ratelimit-limit"]&.to_i
|
|
26
|
+
@rate_limit_remaining = headers["ratelimit-remaining"]&.to_i
|
|
27
|
+
@rate_limit_reset = headers["ratelimit-reset"]&.to_i
|
|
28
|
+
@retry_after = headers["retry-after"]&.to_i
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# code 404
|
|
33
|
+
NotFoundError = Class.new(ServerError)
|
|
34
|
+
|
|
35
|
+
ERRORS = {
|
|
36
|
+
401 => EmailFuse::Error::InvalidRequestError,
|
|
37
|
+
404 => EmailFuse::Error::InvalidRequestError,
|
|
38
|
+
422 => EmailFuse::Error::InvalidRequestError,
|
|
39
|
+
429 => EmailFuse::Error::RateLimitExceededError,
|
|
40
|
+
400 => EmailFuse::Error::InvalidRequestError,
|
|
41
|
+
500 => EmailFuse::Error::InternalServerError
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
attr_reader :headers
|
|
45
|
+
|
|
46
|
+
def initialize(msg, code = nil, headers = {})
|
|
47
|
+
super(msg)
|
|
48
|
+
@code = code
|
|
49
|
+
@headers = headers
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|