Skip to content

Commit 990276a

Browse files
authored
release/v1.0.0 (#146)
1 parent db7a739 commit 990276a

27 files changed

Lines changed: 1252 additions & 157 deletions

CHANGELOG.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
resend (0.26.0)
4+
resend (1.0.0)
55
httparty (>= 0.21.0)
66

77
GEM

examples/audiences.rb

Lines changed: 0 additions & 31 deletions
This file was deleted.

examples/broadcasts.rb

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,39 @@
66

77
Resend.api_key = ENV["RESEND_API_KEY"]
88

9-
# replace with an existing audience id
10-
audience_id = "78b8d3bc-a55a-45a3-aee6-6ec0a5e13d7e"
9+
# replace with an existing segment id
10+
segment_id = "78b8d3bc-a55a-45a3-aee6-6ec0a5e13d7e"
1111

1212
create_params = {
1313
from: "onboarding@resend.dev",
1414
subject: "Hello from Ruby SDK",
15-
audience_id: audience_id,
15+
segment_id: segment_id,
1616
text: "Hello, how are you?",
1717
name: "Hello from Ruby SDK",
1818
}
1919

2020
broadcast = Resend::Broadcasts.create(create_params)
2121
puts "created broadcast: #{broadcast[:id]}"
2222

23+
# Example using deprecated audience_id (still works for backwards compatibility)
24+
create_params_deprecated = {
25+
from: "onboarding@resend.dev",
26+
subject: "Hello from Ruby SDK (deprecated audience_id)",
27+
audience_id: segment_id, # deprecated: use segment_id instead
28+
text: "This example shows audience_id still works",
29+
name: "Broadcast with deprecated audience_id",
30+
}
31+
32+
broadcast_deprecated = Resend::Broadcasts.create(create_params_deprecated)
33+
puts "created broadcast with deprecated audience_id: #{broadcast_deprecated[:id]}"
34+
35+
# Clean up the deprecated example if it's in draft status
36+
retrieved_deprecated = Resend::Broadcasts.get(broadcast_deprecated[:id])
37+
if retrieved_deprecated[:status] == 'draft'
38+
Resend::Broadcasts.remove(broadcast_deprecated[:id])
39+
puts "removed deprecated example broadcast: #{broadcast_deprecated[:id]}"
40+
end
41+
2342
update_params = {
2443
broadcast_id: broadcast[:id],
2544
name: "Hello from Ruby SDK - updated",
@@ -39,10 +58,16 @@
3958
broadcasts = Resend::Broadcasts.list
4059
puts broadcasts
4160

42-
# Example with pagination
43-
paginated_broadcasts = Resend::Broadcasts.list({ limit: 15, after: "broadcast_id_here" })
44-
puts "Paginated broadcasts (limit 15, after broadcast_id_here):"
45-
puts paginated_broadcasts
61+
# Example with pagination - only demonstrate if has_more is true
62+
if broadcasts[:has_more]
63+
# In real usage, you'd use the cursor from the previous response
64+
# For this example, we just show pagination with limit
65+
paginated_broadcasts = Resend::Broadcasts.list({ limit: 5 })
66+
puts "\nPaginated broadcasts (limit 5):"
67+
puts paginated_broadcasts
68+
else
69+
puts "\nNo more broadcasts to paginate through"
70+
end
4671

4772
retrieved = Resend::Broadcasts.get(broadcast[:id])
4873
puts "retrieved #{retrieved[:id]}"

examples/contact_properties.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
Resend.api_key = ENV["RESEND_API_KEY"]
88

99
def example
10-
# Create a contact property with string type
1110
puts "Creating a string contact property..."
1211
string_property = Resend::ContactProperties.create({
1312
key: "company_name",
@@ -18,7 +17,6 @@ def example
1817

1918
property_id = string_property[:id]
2019

21-
# Create a contact property with number type
2220
puts "\nCreating a number contact property..."
2321
number_property = Resend::ContactProperties.create({
2422
key: "age",
@@ -27,30 +25,25 @@ def example
2725
})
2826
puts "Created property: #{number_property}"
2927

30-
# Retrieve a contact property
3128
puts "\nRetrieving contact property by ID..."
3229
retrieved_property = Resend::ContactProperties.get(property_id)
3330
puts "Retrieved property: #{retrieved_property}"
3431

35-
# List all contact properties
3632
puts "\nListing all contact properties..."
3733
all_properties = Resend::ContactProperties.list
3834
puts "All properties: #{all_properties}"
3935

40-
# List contact properties with pagination
4136
puts "\nListing contact properties with pagination..."
4237
paginated_properties = Resend::ContactProperties.list({ limit: 10 })
4338
puts "Paginated properties: #{paginated_properties}"
4439

45-
# Update a contact property
4640
puts "\nUpdating contact property..."
4741
updated_property = Resend::ContactProperties.update({
4842
id: property_id,
4943
fallback_value: "Example Company"
5044
})
5145
puts "Updated property: #{updated_property}"
5246

53-
# Delete a contact property
5447
puts "\nDeleting contact property..."
5548
deleted = Resend::ContactProperties.remove(property_id)
5649
puts "Deleted property: #{deleted}"

examples/contacts.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,22 @@ def example
2929
first_name: "Updated",
3030
}
3131

32-
retrieved = Resend::Contacts.get(audience_id, contact[:id])
32+
retrieved = Resend::Contacts.get(id: contact[:id], audience_id: audience_id)
3333
puts "Retrived contact by ID"
3434
puts retrieved
3535

36-
retrieved_by_email = Resend::Contacts.get(audience_id, contact[:email])
36+
retrieved_by_email = Resend::Contacts.get(email: params[:email], audience_id: audience_id)
3737
puts "Retrived contact by Email"
3838
puts retrieved_by_email
3939

4040
updated = Resend::Contacts.update(update_params)
4141
puts "Updated contact: #{updated}"
4242

43-
contacts = Resend::Contacts.list(audience_id)
43+
contacts = Resend::Contacts.list(audience_id: audience_id)
4444
puts contacts
4545

4646
# Example with pagination
47-
paginated_contacts = Resend::Contacts.list(audience_id, { limit: 10 })
47+
paginated_contacts = Resend::Contacts.list(audience_id: audience_id, limit: 10)
4848
puts "Paginated contacts (limit 10):"
4949
puts paginated_contacts
5050

@@ -62,9 +62,9 @@ def example
6262
puts "Topic created: #{topic}"
6363
topic_id = topic[:id]
6464

65-
# Get contact topics
66-
puts "\nGetting contact topics..."
67-
contact_topics = Resend::Contacts::Topics.get(contact[:id])
65+
# List contact topics
66+
puts "\nListing contact topics..."
67+
contact_topics = Resend::Contacts::Topics.list(id: contact[:id])
6868
puts "Contact topics: #{contact_topics}"
6969

7070
# Update contact topic subscriptions - opt in to the topic
@@ -79,9 +79,9 @@ def example
7979
updated_topics = Resend::Contacts::Topics.update(update_topics_params)
8080
puts "Updated topic subscription: #{updated_topics}"
8181

82-
# Get contact topics again to see the updated subscription
83-
puts "\nGetting contact topics after opt-in..."
84-
contact_topics_after = Resend::Contacts::Topics.get(contact[:id])
82+
# List contact topics again to see the updated subscription
83+
puts "\nListing contact topics after opt-in..."
84+
contact_topics_after = Resend::Contacts::Topics.list(id: contact[:id])
8585
puts "Contact topics after update: #{contact_topics_after}"
8686

8787
# Update contact topic subscriptions - opt out from the topic
@@ -99,10 +99,10 @@ def example
9999
puts "Topic deleted"
100100

101101
# delete by id
102-
del = Resend::Contacts.remove(audience_id, contact[:id])
102+
del = Resend::Contacts.remove(id: contact[:id], audience_id: audience_id)
103103

104104
# delete by email
105-
# del = Resend::Contacts.remove(audience_id, "steve@example.com")
105+
# del = Resend::Contacts.remove(email: "steve@example.com", audience_id: audience_id)
106106

107107
puts "Deleted #{del}"
108108
end

0 commit comments

Comments
 (0)