> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/puiusabin/bun-smtp/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get started with bun-smtp in minutes

# Quickstart

Get your first SMTP server running with bun-smtp in just a few steps.

## Installation

<Steps>
  <Step title="Install bun-smtp">
    Add bun-smtp to your project:

    ```bash theme={null}
    bun add bun-smtp
    ```

    <Info>
      Make sure you have **Bun 1.2.0 or higher** installed. Check your version with `bun --version`.
    </Info>
  </Step>

  <Step title="Create your server file">
    Create a new file called `server.ts`:

    ```typescript server.ts theme={null}
    import { SMTPServer } from "bun-smtp";

    const server = new SMTPServer({
      authOptional: true,
      onData(stream, session, callback) {
        async function drain() {
          const chunks: Uint8Array[] = [];
          for await (const chunk of stream) {
            chunks.push(chunk);
          }
          console.log(`Received ${chunks.length} chunks from ${session.envelope.mailFrom?.address}`);
          callback(null);
        }
        drain().catch(callback);
      },
    });

    await server.listen(2525);
    console.log("SMTP server listening on port 2525");
    ```

    <Note>
      This example sets `authOptional: true` to accept unauthenticated connections. In production, you should implement proper authentication.
    </Note>
  </Step>

  <Step title="Run your server">
    Start the server with Bun:

    ```bash theme={null}
    bun server.ts
    ```

    You should see:

    ```
    SMTP server listening on port 2525
    ```
  </Step>

  <Step title="Test your server">
    Test your server using `curl` or `telnet`. Here's an example using `curl`:

    ```bash theme={null}
    curl --url 'smtp://localhost:2525' \
      --mail-from 'sender@example.com' \
      --mail-rcpt 'recipient@example.com' \
      --upload-file - <<EOF
    From: sender@example.com
    To: recipient@example.com
    Subject: Test Email

    This is a test message.
    EOF
    ```

    Your server should log the received chunks.
  </Step>
</Steps>

## Understanding the Code

Let's break down what's happening in the example:

### SMTPServer Options

```typescript theme={null}
const server = new SMTPServer({
  authOptional: true,  // Allow connections without authentication
  onData(stream, session, callback) {
    // Handle incoming email data
  },
});
```

The `SMTPServer` constructor accepts various options. The most important ones for getting started are:

* **`authOptional`**: Set to `true` to allow unauthenticated connections
* **`onData`**: Callback invoked when email data is ready to be processed

### The onData Callback

```typescript theme={null}
onData(stream, session, callback) {
  async function drain() {
    const chunks: Uint8Array[] = [];
    for await (const chunk of stream) {
      chunks.push(chunk);
    }
    callback(null);  // Signal success
  }
  drain().catch(callback);  // Handle errors
}
```

The `onData` callback receives:

* **`stream`**: A `ReadableStream<Uint8Array>` containing the email data
* **`session`**: An `SMTPSession` object with connection and envelope information
* **`callback`**: Call this with `null` on success, or an error object on failure

<Tip>
  The stream must be consumed before calling the callback. Use a `for await` loop to read all chunks.
</Tip>

### Starting the Server

```typescript theme={null}
await server.listen(2525);
```

The `listen()` method starts the server on the specified port. It returns a Promise that resolves when the server is ready.

## Next Steps

Now that you have a basic server running, you can:

<CardGroup cols={2}>
  <Card title="Add Authentication" icon="lock" href="/guides/authentication">
    Secure your server with SASL authentication
  </Card>

  <Card title="Enable TLS" icon="shield-check" href="/guides/tls">
    Encrypt connections with STARTTLS or implicit TLS
  </Card>

  <Card title="Handle Messages" icon="database" href="/api/callbacks">
    Save emails to a database or forward them
  </Card>

  <Card title="Configure Options" icon="sliders" href="/api/configuration">
    Explore all available server options
  </Card>
</CardGroup>

## Common Patterns

### Save Email to File

```typescript theme={null}
import { SMTPServer } from "bun-smtp";
import { join } from "path";

const server = new SMTPServer({
  authOptional: true,
  onData(stream, session, callback) {
    async function saveEmail() {
      const chunks: Uint8Array[] = [];
      for await (const chunk of stream) {
        chunks.push(chunk);
      }
      
      const buffer = Buffer.concat(chunks);
      const filename = `${session.id}-${Date.now()}.eml`;
      await Bun.write(join("./emails", filename), buffer);
      
      callback(null);
    }
    saveEmail().catch(callback);
  },
});

await server.listen(2525);
```

### Access Envelope Information

```typescript theme={null}
import { SMTPServer } from "bun-smtp";

const server = new SMTPServer({
  authOptional: true,
  onMailFrom(address, session, callback) {
    console.log(`Mail from: ${address.address}`);
    callback();  // Accept the sender
  },
  onRcptTo(address, session, callback) {
    console.log(`Recipient: ${address.address}`);
    callback();  // Accept the recipient
  },
  onData(stream, session, callback) {
    async function drain() {
      const chunks: Uint8Array[] = [];
      for await (const chunk of stream) {
        chunks.push(chunk);
      }
      
      console.log(`Envelope:`, {
        from: session.envelope.mailFrom?.address,
        to: session.envelope.rcptTo.map(r => r.address),
      });
      
      callback(null);
    }
    drain().catch(callback);
  },
});

await server.listen(2525);
```

### Reject Invalid Senders

```typescript theme={null}
import { SMTPServer } from "bun-smtp";
import type { SMTPError } from "bun-smtp";

const server = new SMTPServer({
  authOptional: true,
  onMailFrom(address, session, callback) {
    const allowedDomain = "example.com";
    
    if (!address.address.endsWith(`@${allowedDomain}`)) {
      const error = new Error("Invalid sender domain") as SMTPError;
      error.responseCode = 550;
      return callback(error);
    }
    
    callback();  // Accept the sender
  },
  onData(stream, session, callback) {
    async function drain() {
      const chunks: Uint8Array[] = [];
      for await (const chunk of stream) {
        chunks.push(chunk);
      }
      callback(null);
    }
    drain().catch(callback);
  },
});

await server.listen(2525);
```

<Warning>
  Always validate and sanitize email addresses and data before processing them to prevent security vulnerabilities.
</Warning>
