> ## 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.

# Email client

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

## The client

```ruby theme={null}
client = Paubox::Client.new          # uses global Paubox.configure credentials
client = Paubox::Client.new(         # or per-client credentials
  api_key:  'YOUR_API_KEY',
  api_user: 'YOUR_USERNAME'
)
```

`send_mail` and `deliver_mail` are aliases. `email_disposition` and `message_receipt` are aliases.

## Building a message

```ruby theme={null}
message = Paubox::Message.new(
  from:                    'sender@yourdomain.com',  # required
  to:                      ['alice@example.com'],    # required; array
  subject:                 'Your results are ready', # optional
  reply_to:                'support@yourdomain.com', # optional
  cc:                      ['manager@example.com'],  # optional
  bcc:                     ['audit@example.com'],    # optional
  text_content:            'Plain text body.',       # at least one required
  html_content:            '<p>HTML body.</p>',      # optional
  allow_non_tls:           false,                    # optional; default false
  force_secure_notification: false                   # optional; default false
)
```

### Attachments

Attach files by path using the helper method:

```ruby theme={null}
message.add_attachment('/path/to/report.pdf')
```

Or set the `attachments` attribute directly with an array of hashes (each with `fileName`, `contentType`, and base64-encoded `content`):

```ruby theme={null}
require 'base64'

message.attachments = [
  {
    fileName:    'report.pdf',
    contentType: 'application/pdf',
    content:     Base64.strict_encode64(File.read('/path/to/report.pdf'))
  }
]
```

## Send a message

```ruby theme={null}
response = client.send_mail(message)
puts response[:source_tracking_id]
```

## Check delivery status

```ruby theme={null}
disposition = client.email_disposition(source_tracking_id)

disposition.message_deliveries.each do |delivery|
  puts "#{delivery.recipient} → #{delivery.status.delivery_status}"
  puts "  Opened: #{delivery.status.opened_status}"
end
```

`EmailDisposition` fields:

| Field                | Description                        |
| -------------------- | ---------------------------------- |
| `source_tracking_id` | The tracking ID                    |
| `message_deliveries` | Array of `MessageDelivery` structs |
| `errors`             | Array of `ResponseError` structs   |

Each `MessageDelivery` struct has `recipient` and `status`. The `status` struct has `delivery_status`, `delivery_time`, `opened_status`, and `opened_time`.

Check `disposition.errors?` to detect API-level errors.

Common `delivery_status` values: `delivered`, `opened`, `failed`, `pending`.

## Dynamic templates

Templates use [Handlebars](https://handlebarsjs.com) syntax (`{{variable_name}}`).

### Create a template

```ruby theme={null}
Paubox::DynamicTemplates.create('appointment-confirmation', '/path/to/template.html')
```

### List templates

```ruby theme={null}
templates = Paubox::DynamicTemplates.list
templates.each { |t| puts "#{t[:id]}: #{t[:name]}" }
```

### Get a template

```ruby theme={null}
template = Paubox::DynamicTemplates.find(template_id)
```

### Update a template

```ruby theme={null}
template.update('/path/to/updated-template.html')
# or rename:
template.update('/path/to/updated-template.html', 'new-template-name')
```

### Delete a template

```ruby theme={null}
template.delete
```

### Send a templated message

```ruby theme={null}
message = Paubox::TemplatedMessage.new(
  from:    'appointments@yourclinic.com',
  to:      ['jane@example.com'],
  subject: 'Your appointment is confirmed',
  template: {
    name:   'appointment-confirmation',
    values: {
      first_name: 'Jane',
      date:       '2024-03-15',
      time:       '2:00 PM'
    }
  }
)

response = client.send_mail(message)
```

## Error handling

Methods raise `RestClient::ExceptionWithResponse` on HTTP errors. Rescue it to inspect the response:

```ruby theme={null}
require 'rest-client'

begin
  response = client.send_mail(message)
rescue RestClient::ExceptionWithResponse => e
  puts "HTTP #{e.response.code}: #{e.response.body}"
end
```
