# Quickstart (/docs/v/0.4.0/getting-started/quickstart)



Install the scoped package with the package manager your app already uses:

<PackageInstallTabs />

The SDK and CLI work in server-side Node 20+ and Bun runtimes. The installed CLI command is named `email-sdk`. If you only need the CLI for a quick check, run `npx --yes --package @opencoredev/email-sdk email-sdk ...` instead. See <a href="/docs/v/0.4.0/getting-started/install">Install</a> for the package and CLI distinction.

## Choose a first adapter [#choose-a-first-adapter]

If you are new to Email SDK, start with Resend. It has the shortest setup path, supports the common transactional fields, and is the default example throughout these docs.

Use Postmark, SendGrid, AWS SES, Mailgun, or Brevo when your app needs broader provider-specific controls. Use SMTP when you already have a trusted SMTP service and only need address fields, headers, and plain message delivery.

## Send through Resend [#send-through-resend]

Set `RESEND_API_KEY`, then create a client with the Resend adapter.

```ts
import { createEmailClient } from "@opencoredev/email-sdk";
import { resend } from "@opencoredev/email-sdk/resend";

const email = createEmailClient({
  adapters: [resend({ apiKey: process.env.RESEND_API_KEY! })],
});

await email.send({
  from: "Acme <hello@acme.com>",
  to: "user@example.com",
  subject: "Welcome to Acme",
  text: "Your account is ready.",
});
```

## Check the send result [#check-the-send-result]

`send` resolves with the normalized adapter response. The `provider` value tells you which adapter
actually handled the send.

```ts
const result = await email.send(message);

console.log(result.provider);
console.log(result.id);
```

If the adapter returns a message ID, Email SDK exposes it through the normalized `id` field. Some
adapters also include `messageId` as an alias when the provider uses that name directly. Provider
responses are still available through `raw` when an adapter includes them.

## Verify from the CLI [#verify-from-the-cli]

Use `doctor` to check that the selected adapter has the required environment variables.

```bash
RESEND_API_KEY="re_..." npx --yes --package @opencoredev/email-sdk email-sdk doctor --adapter resend
```

Use `--dry-run` to validate the message shape and adapter field support without sending email.

```bash
npx --yes --package @opencoredev/email-sdk email-sdk send \
  --adapter resend \
  --from "Acme <hello@acme.com>" \
  --to "user@example.com" \
  --subject "Hello" \
  --text "It works" \
  --dry-run
```

When the package is installed in your project, the same command can run through the installed binary:

```bash
RESEND_API_KEY="re_..." npx email-sdk doctor --adapter resend
```

## Add SMTP fallback [#add-smtp-fallback]

Add SMTP when you want a second route for the same transactional email. The SMTP adapter is built in
and does not require Nodemailer. When SMTP auth is configured on a non-secure connection, Email SDK
upgrades with STARTTLS before authenticating.

Only use fallback adapters that can send the same message shape. For example, SMTP supports address
fields and headers, but not provider-only fields like tags, metadata, or attachments.

```ts
import { createEmailClient } from "@opencoredev/email-sdk";
import { resend } from "@opencoredev/email-sdk/resend";
import { smtp } from "@opencoredev/email-sdk/smtp";

export const email = createEmailClient({
  adapters: [
    resend({ apiKey: process.env.RESEND_API_KEY! }),
    smtp({
      host: "smtp.purelymail.com",
      port: 587,
      auth: {
        user: process.env.SMTP_USER!,
        pass: process.env.SMTP_PASS!,
      },
    }),
  ],
  fallback: ["smtp"],
});
```

Your application still sends the same way:

```ts
await email.send({
  from: "Acme <hello@acme.com>",
  to: "user@example.com",
  subject: "Receipt",
  text: "Thanks for your order.",
});
```
