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

# Rust SDK email client

> Full reference for the Paubox Rust SDK email client: building messages, sending email, tracking delivery, and error handling.

## Creating a client

```rust theme={null}
// From environment variables (recommended)
let client = PauboxClient::from_env()?;

// Direct constructor
let client = PauboxClient::new("YOUR_API_KEY");

// Builder (custom timeout, base URL for testing)
let client = PauboxClient::builder()
    .api_key("YOUR_API_KEY")
    .timeout(Duration::from_secs(15))
    .build()?;
```

See [Authentication](/rust-sdk/authentication) for details on all three options.

## Building a message

Use `Message::builder()` to compose a message. All methods take `impl Into<String>` or iterables:

```rust theme={null}
use paubox::Message;

let message = Message::builder()
    .from("sender@yourdomain.com")           // required
    .to(["alice@example.com"])               // required; accepts any iterable
    .subject("Your results are ready")       // required
    .text_content("Plain text body.")        // at least one of text/html required
    .html_content("<p>HTML body.</p>")       // optional
    .reply_to("support@yourdomain.com")      // optional
    .cc(["manager@example.com"])             // optional
    .bcc(["audit@example.com"])              // optional
    .allow_non_tls(false)                    // optional; default false
    .force_secure_notification(true)         // optional
    .build()?;
```

`.build()` validates required fields and returns `Err(PauboxError::Validation(...))` if any are missing.

### Attachments

The `from_bytes` constructor base64-encodes the data automatically; no manual encoding needed:

```rust theme={null}
use paubox::Attachment;
use std::fs;

let data = fs::read("report.pdf")?;

let attachment = Attachment::from_bytes("report.pdf", "application/pdf", &data);
```

If you already have base64-encoded content:

```rust theme={null}
let attachment = Attachment::from_base64("report.pdf", "application/pdf", encoded_string);
```

Add attachments to a message via the builder:

```rust theme={null}
let message = Message::builder()
    // ...other fields...
    .attachment(attachment)
    .build()?;
```

## Send a message

```rust theme={null}
let response = client.send_message(&message).await?;
println!("Tracking ID: {}", response.source_tracking_id);
```

`SendResponse` fields:

| Field | Description |
| - | - |
| `source_tracking_id` | Use to check delivery status |
| `message` | Status message from the API |

## Check delivery status

```rust theme={null}
let disposition = client
    .get_email_disposition(&response.source_tracking_id)
    .await?;

for delivery in &disposition.message_deliveries {
    println!(
        "{} → {} (opened: {})",
        delivery.recipient,
        delivery.delivery_status,
        delivery.opened_status
    );
}
```

`MessageDelivery` fields:

| Field | Description |
| - | - |
| `recipient` | Email address |
| `delivery_status` | e.g. `delivered`, `failed`, `pending` |
| `delivery_time` | ISO 8601 timestamp, if delivered |
| `opened_status` | `opened` or `unopened` |
| `opened_time` | ISO 8601 timestamp, if opened |

## Scheduled send

Schedule a message for future delivery, check its status, reschedule, or cancel it.

### Schedule a message

```rust theme={null}
let response = client
    .schedule_message(&message, "2025-12-25T15:00:00Z")
    .await?;
println!("Tracking ID: {}", response.source_tracking_id);
println!("Scheduled for: {}", response.scheduled_at);
```

`scheduled_at` must be an ISO 8601 UTC datetime string in the future and within 30 days.

### Get scheduled message status

```rust theme={null}
let status = client.get_scheduled_message("source-tracking-id").await?;
println!("State: {}", status.state);          // "pending", "sent", "cancelled"
println!("Scheduled for: {}", status.scheduled_at);
```

`ScheduledMessageStatus` fields:

| Field | Description |
| - | - |
| `source_tracking_id` | Tracking ID |
| `scheduled_at` | Scheduled delivery time |
| `state` | `pending`, `sent`, `cancelled` |
| `message_id` | Internal message ID |

### Reschedule a message

```rust theme={null}
let response = client
    .reschedule_message("source-tracking-id", "2025-12-26T10:00:00Z")
    .await?;
println!("Rescheduled to: {}", response.scheduled_at);
```

### Cancel a scheduled message

```rust theme={null}
let response = client
    .cancel_scheduled_message("source-tracking-id")
    .await?;
println!("Cancelled: {} (state: {})", response.source_tracking_id, response.state);
```

## Health check

```rust theme={null}
client.api_status().await?;
```

Returns `Ok(())` if the API is reachable, or a `PauboxError` if not.

## Error handling

All methods return `Result<T, PauboxError>`. Match on the variants to handle specific conditions:

```rust theme={null}
use paubox::PauboxError;

match client.send_message(&message).await {
    Ok(response) => println!("Sent: {}", response.source_tracking_id),
    Err(PauboxError::Auth(msg)) => eprintln!("Invalid credentials: {}", msg),
    Err(PauboxError::Http { status, body }) => {
        eprintln!("HTTP {}: {}", status, body);
    }
    Err(PauboxError::Validation(msg)) => eprintln!("Invalid message: {}", msg),
    Err(e) => eprintln!("Error: {}", e),
}
```

`PauboxError` variants:

| Variant | When it occurs |
| - | - |
| `Auth(String)` | HTTP 401: invalid or missing credentials |
| `Http { status, body }` | Non-2xx response other than 401 |
| `Request(reqwest::Error)` | Network or TLS failure |
| `Deserialize(serde_json::Error)` | Unexpected response format |
| `Validation(String)` | Missing required message field |
| `EnvVar(String)` | Missing environment variable in `from_env()` |
| `Url(url::ParseError)` | URL construction failure |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.