Postscale Ruby SDK
Official Ruby SDK for the Postscale email API.
Install
gem install postscale
Or add to your Gemfile:
gem 'postscale'
Requires Ruby 3.0 or newer.
Send Email
require 'postscale'
postscale = Postscale::Client.new(api_key: ENV.fetch('POSTSCALE_API_KEY'))
result = postscale.emails.send(
from: 'hello@example.com',
to: ['user@example.com'],
subject: 'Welcome!',
html_body: '<strong>It works.</strong>'
)
if result.error
raise "#{result.error.code}: #{result.error.}"
end
puts result.data['message_id']
The SDK keeps Postscale API-native field names. Use html_body,
text_body, template_id, and unsubscribe_scope; the MVP SDK does not add
html or text aliases.
Configuration
postscale = Postscale::Client.new(
api_key: ENV['POSTSCALE_API_KEY'],
base_url: 'https://api.postscale.io',
timeout: 30,
max_retries: 3,
headers: {}
)
| Option | Description | Default |
|---|---|---|
api_key |
Your Postscale API key. Falls back to POSTSCALE_API_KEY. |
Required |
base_url |
API base URL | https://api.postscale.io |
timeout |
Request timeout in seconds | 30 |
max_retries |
Retries for idempotent GET, HEAD, and OPTIONS requests |
3 |
headers |
Additional default request headers | {} |
If no base URL is passed, the SDK reads POSTSCALE_BASE_URL and then falls
back to https://api.postscale.io.
Results and Errors
Every API method returns a result object:
result = postscale.domains.list(limit: 10)
if result.error
warn "#{result.error.code}: #{result.error.}"
warn result.error.request_id
else
puts result.data
end
API errors are returned as Postscale::APIError objects inside
result.error. Configuration and local validation errors are raised before a
request is sent.
Attachments
= Postscale.('invoice.pdf', 'application/pdf')
result = postscale.emails.send(
from: 'billing@example.com',
to: ['customer@example.com'],
subject: 'Invoice',
text_body: 'Attached.',
attachments: []
)
Attachment helpers return API-native hashes with filename, content, and
content_type. Client-side checks enforce the documented limits: 10
attachments, 25 MB per attachment, and 50 MB total decoded attachment payload.
Webhook Verification
result = Postscale.verify_webhook_signature(
raw_body,
request.get_header('HTTP_X_POSTSCALE_SIGNATURE'),
[current_secret, previous_secret]
)
halt 401 unless result.valid?
The verifier requires the Postscale signature format:
t=<unix_seconds>,v1=<hex_hmac_sha256>, signed over <t>.<raw_body>. It
supports multiple v1= signatures and multiple candidate secrets for rotation
windows.
API Reference
Emails
postscale.emails.send(...)
postscale.emails.send_batch(emails: [...])
postscale.emails.list(...)
postscale.emails.get(email_id)
postscale.emails.list_events(email_id)
Domains
postscale.domains.create(domain: 'example.com')
postscale.domains.list
postscale.domains.get(domain_id)
postscale.domains.update(domain_id, active: true)
postscale.domains.verify(domain_id)
postscale.domains.dns(domain_id)
postscale.domains.delete(domain_id)
DKIM
postscale.dkim.generate(domain_id, selector: 's1')
postscale.dkim.list(domain_id)
postscale.dkim.rotate(domain_id, old_selector: 's1', new_selector: 's2')
postscale.dkim.deactivate(domain_id, 's1')
Inbound
postscale.inbound.list(...)
postscale.inbound.get(email_id)
postscale.inbound.download_attachment(email_id, attachment_id)
Suppressions
postscale.suppressions.list
postscale.suppressions.add(email: 'user@example.com', reason: 'hard_bounce')
postscale.suppressions.check('user@example.com')
postscale.suppressions.remove('user@example.com')
postscale.suppressions.import_preview(...)
postscale.suppressions.import_job(job_id)
postscale.suppressions.commit_import(job_id)
Templates
postscale.templates.create(...)
postscale.templates.list
postscale.templates.get(template_id)
postscale.templates.update(template_id, ...)
postscale.templates.preview(template_id, ...)
postscale.templates.delete(template_id)
Webhooks
postscale.webhooks.create(url: 'https://example.com/webhooks', events: ['email.delivered'])
postscale.webhooks.list
postscale.webhooks.deliveries
postscale.webhooks.endpoint_deliveries(webhook_id)
postscale.webhooks.rotate_secret(webhook_id)
postscale.webhooks.delete(webhook_id)
postscale.webhooks.verify_signature(raw_body, signature_header, secrets)
Warming, Stats, Usage, and Trust
postscale.warming.get_status(domain_id)
postscale.warming.history(domain_id)
postscale.warming.start(domain_id)
postscale.warming.pause(domain_id)
postscale.warming.resume(domain_id)
postscale.stats.aggregate(domain_id)
postscale.stats.daily(domain_id)
postscale.stats.hourly(domain_id)
postscale.stats.isp(domain_id)
postscale.usage.summary
postscale.trust.get_review_request
postscale.trust.create_review_request(...)
Testing
rake test
License
MIT