dart_resend 2.0.0
dart_resend: ^2.0.0 copied to clipboard
A production-ready Dart SDK for the complete Resend email API.
dart_resend
A production-ready, community-maintained Dart SDK for the complete Resend API.
The public surface tracks the official Resend API reference and its canonical OpenAPI specification.
dart_resend 2.0 provides typed request and response models, cursor pagination,
request metadata, predictable exceptions, local validation, dependency-injected
HTTP transport, and first-class support for every current Resend resource.
Developed with 💙 and maintained by coderave
Important notes #
- Keep API keys on a trusted server. Never embed a Resend API key in a web, Flutter, mobile, desktop, or other distributed client. Route those requests through your own authenticated backend.
- 2.0.0 is an intentional breaking redesign. The singleton,
ResendClient,ResendResult, legacy feature clients, and legacy response classes were removed. See the migration guide. - Audiences were removed. Resend's current API uses global Contacts and Segments. The package no longer exposes the retired Audiences resource.
- Suppressions are private beta. The API is implemented, but calls only work for Resend teams with access to the gated feature.
Install #
dart pub add dart_resend
The package requires Dart 3.8 or newer.
Quick start #
import 'package:dart_resend/dart_resend.dart';
Future<void> sendEmail(String apiKey) async {
final Resend resend = Resend(apiKey: apiKey);
try {
final ResendResponse<ResendId> response = await resend.emails.send(
SendEmailRequest.raw(
from: 'Acme <onboarding@resend.dev>',
to: <String>['delivered@resend.dev'],
subject: 'Hello from dart_resend',
html: '<strong>It works!</strong>',
text: 'It works!',
),
);
print(response.data.id);
} finally {
resend.close();
}
}
Run the complete quick start with an environment variable:
RESEND_API_KEY=re_... dart run example/main.dart
See the runnable example.
Client lifecycle #
Create one Resend instance per application or service and reuse it. Calling
close() releases the internally owned HTTP client and is safe to do more than
once. Calls made after closing fail with StateError.
When an http.Client is injected, it remains caller-owned by default. Set
closeClient: true if Resend.close() should close the injected client too.
The constructor also accepts a request timeout, defaultHeaders, and custom
baseUri for tests or compatible gateways. See
useConfiguredClient.
OAuth registration and token endpoints do not require an API key. Use
Resend.unauthenticated() for those calls and an authenticated Resend client
for team resources and OAuth grant management.
Responses, pagination, and errors #
Every network method returns Future<ResendResponse<T>>. The response contains
the decoded data, HTTP statusCode, immutable lowercase headers, Resend
requestId, and parsed rateLimit metadata. Response models also retain their
complete immutable payload in json, so newly added server fields remain
available before the SDK adds typed getters.
List operations accept PaginationOptions(limit:, after:, before:) and return
ResendPage<T>, whose data and hasMore fields drive cursor iteration.
after and before are mutually exclusive; limits must be between 1 and 100.
See cursor iteration and
response metadata.
Failures are thrown as typed exceptions:
ResendApiExceptionfor non-2xx API responses, including the status, error name, request ID, headers, parsed details, and raw body.ResendTimeoutExceptionwhen the configured timeout expires.ResendNetworkExceptionfor other transport failures.ResendDecodeExceptionwhen a successful response cannot be decoded.ArgumentError,RangeError, orStateErrorfor invalid local usage.
See the complete error-handling example.
Complete feature and example index #
Every public Resend operation is demonstrated below. The linked files are part of the analyzed package examples and use only the public library entrypoint.
Emails #
emails.sendwith raw HTML/text, recipients, headers, tags, inline bytes, Base64 and remote attachments, topic, and idempotencyemails.sendwith a published template and variablesemails.sendwith scheduled deliveryemails.sendBatchwith raw and template emails, permissive validation, tags, and idempotencyemails.listemails.retrieveemails.updateto rescheduleemails.cancelemails.listSentAttachmentsemails.retrieveSentAttachmentemails.listReceivedemails.retrieveReceivedwith inline-image format controlemails.listReceivedAttachmentsemails.retrieveReceivedAttachment
Batch sends support tags but not attachments or scheduled_at. A batch may
contain 1–100 emails and can use strict all-or-nothing or permissive per-item
validation.
Domains #
domains.createwith region, TLS, tracking, return path, and capabilitiesdomains.listdomains.retrieveand DNS recordsdomains.updatedomains.verifydomains.deletedomains.claimdomains.retrieveClaimdomains.verifyClaim
Domain DNS models preserve unknown record kinds and types for forward compatibility. A configured tracking subdomain can currently be replaced and reverified, but not removed.
API keys #
The token returned by apiKeys.create is shown only once; store it in a secret
manager and never log it.
Broadcasts #
broadcasts.createas a draftbroadcasts.createand schedule immediatelybroadcasts.listbroadcasts.retrievebroadcasts.update, including clearing a topicbroadcasts.sendnow or laterbroadcasts.deleteor cancel
Templates #
templates.createwith string, number, boolean, object, and list variablestemplates.listtemplates.retrieveby ID or aliastemplates.updatetemplates.publishtemplates.duplicatetemplates.delete- Send a published template
Contacts and imports #
contacts.createwith custom properties, segments, and topicscontacts.listcontacts.listfiltered by segmentcontacts.retrieveby ID or emailcontacts.update, clear names, and remove property valuescontacts.deleteby ID or emailcontacts.listSegmentscontacts.addToSegmentcontacts.removeFromSegmentcontacts.listTopicscontacts.updateTopicswith opt-in and opt-out valuescontacts.imports.createwith CSV mapping, conflict behavior, segments, and topicscontacts.imports.listwith status filteringcontacts.imports.retrieveand row counts
Contacts are global. Use segments for grouping and topics for granular contact
preferences; use unsubscribed for the global broadcast preference.
Segments #
Topics #
topics.createwith default subscription and public/private visibilitytopics.listwith cursor paginationtopics.retrievetopics.update, including visibilitytopics.delete
Contact properties #
contactProperties.createwith typed fallback valuescontactProperties.listcontactProperties.retrievecontactProperties.updateor clear a fallbackcontactProperties.delete
Webhooks #
webhooks.createand every documented event typewebhooks.listwebhooks.retrieveand its signing secretwebhooks.updatewebhooks.delete- Verify the raw payload and
svix-*headers locally
Never parse and re-encode a webhook body before verification. Verification uses
the raw request body and throws ResendWebhookVerificationException for an
invalid signature, timestamp, or payload.
API logs #
Automations and runs #
- Every condition operator plus
allandanygroups - Forward-compatible custom automation steps
automations.createwith trigger, wait, condition, email, delay, contact update, segment, contact-delete, variables, and every branch typeautomations.listwith status filteringautomations.retrieveand its graphautomations.updateautomations.stopautomations.deleteautomations.runs.listwith status filteringautomations.runs.retrievewith step diagnostics
Automation graph builders validate the trigger, unique keys, endpoints, reachability, connection branches, and duplicate connections before sending.
Custom events #
events.createwith every schema typeevents.listevents.retrieveby ID or nameevents.updateor clear the schemaevents.deleteby ID or nameevents.sendto a contact IDevents.sendto an email address
Suppressions (private beta) #
These calls require private-beta access on the authenticated Resend team:
suppressions.addsuppressions.addBatchsuppressions.retrieveby ID or emailsuppressions.listwith origin filteringsuppressions.removesuppressions.removeBatchby emailsuppressions.removeBatchby ID
OAuth 2.1 and PKCE #
Resend.unauthenticatedandoauth.registerOAuthPkcePair.generateandoauth.authorizationUriOAuthPkcePair.fromVerifieroauth.exchangeCodeoauth.refreshoauth.revokeToken- Create a
Resendclient from an OAuth access token oauth.listGrantswith team authenticationoauth.revokeGrantwith team authentication
Use a cryptographically random state, bind it to the browser session, and
store the PKCE verifier securely until the callback. OAuth access and refresh
tokens are secrets and must remain server-side. Authorization URLs default to
https://api.resend.com/oauth/authorize; override authorizationBaseUri only
for an intentional compatible service or test environment.
Version 2 migration #
Version 2 deliberately does not include compatibility shims for the old API. Read MIGRATION.md for old-to-new call mappings, the new exception model, and the Audiences-to-Segments migration.
Contributing #
See CONTRIBUTING.md for package development, tests, coverage, documentation, and pull-request requirements.