Dart SDK
A Dart SDK for sending and receiving emails over the Nostr protocol using NIP-59 gift-wrapped messages.
There is also a JavaScript SDK for Node and the browser.
Installation
dart pub add nostr_mail
Or add to your pubspec.yaml:
dependencies:
nostr_mail: ^3.2.1
Features
- Send to Nostr users, to legacy addresses through a bridge, or both at once
- NIP-59 gift wrapping, with signed rumors and public emails when you want them
- Attachments of any size, stored encrypted on Blossom
- Local store on drift (SQLite) with full-text search
- Folders, read state and stars as NIP-32 labels
- Settings synced across devices with NIP-78
- Scheduled sending through a Scheduler DVM
- Offline-first: queued sends and uploads survive a restart
What you provide
The client does not own its infrastructure. You build it and hand it over, so it can share what your app already runs.
Quick Start
import 'dart:io';
import 'package:drift/native.dart';
import 'package:ndk/ndk.dart';
import 'package:nostr_mail/nostr_mail.dart';
import 'package:sembast/sembast_io.dart' hide Filter;
import 'package:sync_engine_shim_for_ndk/sync_engine_shim_for_ndk.dart';
void main() async {
final ndk = Ndk(NdkConfig(
cache: MemCacheManager(),
eventVerifier: Bip340EventVerifier(),
));
final keyPair = Bip340.generatePrivateKey();
ndk.accounts.loginPrivateKey(
pubkey: keyPair.publicKey,
privkey: keyPair.privateKey!,
);
final database = NostrMailDatabase(NativeDatabase(File('nostr_mail.sqlite')));
final db = await databaseFactoryIo.openDatabase('emails.db');
final blossomCache = await IdbBlossomCache.open(factory: idbFactorySembastIo);
final syncEngine = SyncEngine(ndk, db: db);
final client = await NostrMailClient.create(
ndk: ndk,
database: database,
db: db,
blossomCache: blossomCache,
syncEngine: syncEngine,
);
await client.send(
to: [await resolveRecipient(to: 'bob@example.com', ndk: ndk)],
subject: 'Hello from Nostr!',
body: 'This email was sent over the Nostr protocol.',
);
client.onEmail.listen((email) {
print('New email: ${email.mime.decodeSubject()}');
});
}
Remote signers
With a remote signer, give ndk a cache manager that persists
(SembastCacheManager). ndk keeps the plaintext it decrypted there, so
approvals already granted are not asked for again.
Quick Navigation
Recipients, transports, scheduling, public emails
Sync, mailbox listing, labels and folders
The drift store, Blossom cache, clearing an account
The client surface, models and exceptions
The same protocol from Node and the browser