All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.21.1 - 2026-02-23
- Many fields that were previously private in
eventsare now public
0.21.0 - 2026-02-03
- The following fields from
InboundAttachmentare notOptions:filenamecontent_dispositionsize
0.20.0 - 2026-01-18
- Renamed
ErrorKind::ValidationError403->ErrorKind::ValidationError403Email
ErrorKind::ValidationError403DomainEmailEventType::EmailSuppressed,EmailEventType::EmailScheduled
ListResponse::is_emptyandListResponse::lenare no longerconst(#33)
0.19.0 - 2025-10-29
- optional
text,htmlfields inBroadcast. - 7 new Templates endpoints
- 5 new Topics endpoints
- and 2 new contact-topic endpoints
- 4 new Inbound endpoints
- 2 new Email endpoints
- 5 new Webhook endpoints
- Added
email.receivedandemail.failedwebhook event types - 3 new contact-segment methods
- Added 5 new contact properties endpoints
- renamed
Audiences->Segments - renamed
Email.Attachment->Email.CreateAttachment - renamed
ContactData->CreateContactOptions - Contact methods no longer require an
audience_idlet contact = CreateContactOptions::new("steve.wozniak@gmail.com") .with_first_name("Steve") .with_last_name("Wozniak") + .with_audience_id(&audience_id); .with_unsubscribed(false); -let _contact_id = resend.contacts.create(&audience_id, contact).await?; +let _contact_id = resend.contacts.create(contact).await?; - Contact
get_*,update_*anddelete_*methods have been merged intoget,updateand
delete
0.18.0 - 2025-09-16
This is unfortunately going to break all endpoint::list calls due to backend changes. The good
news is that you can get more or less the old behavior by adding:
+use resend_rs::list_opts::ListOptions;
let _emails = resend
.emails
.list(
+ ListOptions::default()
).await?;Email.last_eventis now a strongly typedEmailEventenum instead of a string.- Generalized
types::ListEmailOptstolist_opts::ListOptsso it can be used in other endpoints - Generalized
types::ListEmailResponsetolist_opts::ListResponse, same as above^ - The following endpoints now take a
ListOptionsargument and returnListResponse<T>api_keys::listaudiences::listbroadcasts::listcontacts::listdomains::list
ListApiKeyResponseListAudienceResponseListBroadcastResponseListContactResponseListDomainResponse
0.17.1 - 2025-09-03
- The resend backend renamed the header used by the
batch::send_with_batch_validationmethod
0.17.0 - 2025-09-02
Vec<CreateEmailOptions>now implementsIdempotent(should've added this earlier, oops)- Support for batch validation modes via
BatchSvc::send_with_batch_validation(andSendEmailBatchResponse). - New endpoint:
emails::list
0.16.1 - 2025-08-08
Attachment::with_content_id, will replaceAttachment::with_inline_content_idin the next major release.
0.16.0 - 2025-08-08
Attachment::with_inline_content_idClient::with_configallowing to create aResendclient with custom configuration (#28)
Attachmentfields were made private to avoid future breaking changes when new fields are added. Use theAttachmentfor setting the fields instead.Tagfields were also made private.
0.15.0 - 2025-05-09
- A bunch of
#[must_use]and#[inline].
- Updated
ErrorKindto match https://resend.com/docs/api-reference/errors - Changed how
idempotency_keys work;-
CreateEmailBaseOptionsno longer has anidempotency_keyfield, rather itswith_idempotency_keymethod returns an instance of the newIdempotent<T>struct which is then consumed by methods that support it. Because the methods that support it (sendfor now) now takeInto<Idempotent<CreateEmailBaseOptions>>andCreateEmailBaseOptionsautomatically implements that, existing code should just work.In order for batch emails to work similarly, a new trait
idempotent::IdempotentTraitwas created. Importing that adds thewith_idempotency_keyto iterators of typeCreateEmailBaseOptions. This was all done to fix the bug I mention later.
-
CreateDomainOptions::with_custom_return_pathnow takesInto<String>so&strcan also be used
ErrorKind::InvalidToAddressErrorKind::InvalidScope- removed already deprecated
contacts::get, usecontacts::get_by_idorcontacts::get_by_emailinstead
- Sending batch emails now correctly take 1 idempotency key instead of one per email.
0.14.1 - 2025-04-29
CreateDomainOptions::with_custom_return_path
0.14.0 - 2025-04-22
contacts::get_by_idandcontacts::get_by_email
- Deprecated
contacts::getin favor ofcontacts::get_by_idandcontacts::get_by_email
- Removed deprecated
contacts::updatefunction (usecontacts::update_by_id/contacts::update_by_email)
0.13.0 - 2025-04-20
CreateEmailBaseOptions::with_idempotency_key
- Moved
SendEmailBatchResponsefromemailtobatchmodule - Made
LocatedError,DebugResultandCLIENT(all used for testing internals) private (they were accidentally public before, very unlikely they were used by anyone)
0.12.1 - 2025-03-26
broadcasts::updateandUpdateBroadcastOptions,UpdateBroadcastResponse
0.12.0 - 2025-02-25
- WASM support
0.11.2 - 2025-01-18
ErrorKindnow implementsPartialEq, Eq(#23)
0.11.1 - 2025-01-16
Contacts::update_by_id,Contacts::update_by_email
Contacts::updatehas been deprecated in favor of the above methods. The ability to use emails instead of ids was just added to the Resend backend.
0.11.0 - 2025-01-13
BroadcastId::new
- Made the following methods require
&strinstead of their specific ID types. This was changed to make their usage a bit simpler from the user's perspective, after all, the ID types were meant to be more like hints that a string is of an id type, rather than having specific properties in the program itself. The ID types are still used in the return types for this reason and they are also all constructable in case you want to use them. All the ID types dereference to a string so&IdTypeis equivalent to a&str(you might need to make this change if you were using any ID types directly before).ApiKeys::deleteAudiences::deleteBroadcasts::get,deleteDomains::delete
SendBroadcastOptions::newis no longerconst
0.10.0 - 2024-12-13
broadcastsmoduleCreateEmailBaseOptions::with_reply_multiple
- Made
CreateEmailBaseOptions.reply_tofield private - The following changes were made to ensure IDs are consumed upon deletion to avoid accidetally
reusing them. Of course it is still possible to clone them if necessary.
api_keys::deletenow takesApiKeyIdinstead of&straudiences::deletenow takesAudienceIdinstead of&strdomains::deletenow takesDomainIdinstead of&str
0.9.2 - 2024-11-29
- Added webhook support with the
eventsmodule
0.9.1 - 2024-08-13
- renamed
CreateEmailBaseOptions::with_scheduledtowith_scheduled_at - renamed
emails::cancel_scheduletocancel
0.9.0 - 2024-08-12
Yanked due to some method naming, use 0.9.1 instead.
email.scheduled_atfield (andemails::with_scheduledmethod for setting it)emails::updatemethodemails::cancel_schedulemethod
-
The following structs had all their fields made private in order to prevent future breaking changes when new fields are added. Simply use the relevant builder methods instead. GitHub issue.
CreateEmailBaseOptionsContactDataContactChangesCreateDomainOptionsDomainChangesUpdateEmailOptions
0.8.1 - 2024-07-11
Email.textis now optional
- The
cc,bccandtextfields of theEmailstruct are nullable which broke deserialization. It now works as expected.
0.8.0 - 2024-07-05
rate_limitmoduleError::RateLimit
0.7.0 - 2024-07-01
Attachment::with_content_typemethod andcontent_typefieldError::Parsevariant
- HTML server responses instead of proper JSON errors (which should mostly happen in outages) now have better error messages
0.6.0 - 2024-06-16
RATE_LIMITtoRESEND_RATE_LIMITto avoid potential collisions with other libs
- Outdated doc comment from
Client::user_agent
0.5.2 - 2024-06-10
DomainChanges::with_tlsmethod- docs for
Domain.Tlsenum options
0.5.1 - 2024-06-08
- Moved Github URLs from
resend-rstoresend-rust(no code changes)
0.5.0 - 2024-06-08
DomainChanges.tls- Rate limiting (default 9/s), configurable with
RATE_LIMITenv variable (async only)
- renamed
SendEmailtoCreateEmailBaseOptions - renamed
email.retrievetoemail.get - renamed
SendEmailResponsetoCreateEmailResponse - renamed
ApiKeyDatatoCreateApiKeyOptions - renamed
domains.DomainDatatoCreateDomainOptions email.sendnow returns aCreateEmailResponseinstead of anEmailIdbatch.sendnow returns aVec<CreateEmailResponse>instead of aVec<EmailId>audiences.createnow returnsCreateAudienceResponseinstead ofAudienceIdcontacts.updatenow returnsUpdateContactResponsedomains.updatenow returnsUpdateDomainResponse- moved batch related stuff to a new module
email.send_batchis nowbatch.send- moved error stuff from
configto their ownerrormodule - removed
[...]Idtypes from function arguments - implemented
Deref<str>for all[...]Idtypes DomainRecordhas been converted to an enum for better/more detailed type handlingDomain.recordsis now optionalEmail.tois now a veccontacts.delete_by_emailandcontacts.delete_by_contact_idnow return thedeletedboolean- Renamed
ClienttoResend Domainno longer has thedns_providerfield.Domain.deletenow returns aDeleteDomainResponseEmail.Tag.valueis no longer an optionalEmail.htmlandEmail.reply_toare now both optional
- removed ability to configure user agent via
RESEND_USER_AGENT(this is no longer configuable) email.with_value, use thenewconstructor insteadimpl<T: AsRef<str>> From<T> for Tagis removed since Tag now also needs a valueContactChanges.emailandContactChanges.with_email
0.4.0 - 2024-05-01
@martsokha basically rewrote the entire repository 0_0
(pr)
The crate now supports the entire Resend API surface, check the docs for examples.
0.3.0 - 2024-02-06
-
Mail::newnow accepts a list oftoaddresses and thus supports sending an email to multiple recipients.// Before: let mail = Mail::new("from1", "to1", "subject1", "html1"); // Now let mail = Mail::new("from1", &["to1"], "subject1", "html1");
0.2.0 - 2023-07-10
Disabled reqwest's default features and enabled rustls-tls.
0.1.0 - 2023-07-10
Initial release.