Ruby SDK
Complete guide to the OneShotMail Ruby SDK -- installation, API reference, Cucumber and RSpec integration.
Installation
gem install oneshot-mail
Or add to your Gemfile:
gem "oneshot-mail"
Then run bundle install. Requires Ruby 3.0+.
Configuration
From environment variable
require "oneshot"
# Reads ONESHOT_API_KEY from environment automatically
client = OneShot::Client.new
Explicit API key
client = OneShot::Client.new(api_key: "osm_live_your_key")
Custom base URL
client = OneShot::Client.new(
api_key: "osm_live_your_key",
base_url: "http://localhost:4566/v1"
)
API Reference
create(ttl:, label:, mode:)
Create a new one-shot email address. Returns a Hash with address details.
| Parameter | Type | Default | Description |
|---|---|---|---|
ttl: | Integer | 3600 | TTL in seconds. |
label: | String | nil | Optional label for filtering. |
mode: | String | "receive" | "receive" or "send". |
addr = client.create(ttl: 300, label: "signup-test")
puts addr["id"] # "abc123xyz789def456"
puts addr["address"] # "abc123xyz789def456@in.oneshotemail.com"
puts addr["status"] # "waiting"
get(address_id)
Retrieve an address and its current status.
addr = client.get("abc123xyz789def456")
if addr["status"] == "received"
puts "From: #{addr['email']['from']}"
puts "Subject: #{addr['email']['subject']}"
end
get_email(address_id)
Retrieve the full parsed email content.
email = client.get_email("abc123xyz789def456")
puts email["from"] # "noreply@example.com"
puts email["subject"] # "Verify your account"
puts email["text_body"] # "Click here to verify..."
puts email["html_body"] # "<html>...</html>"
puts email["attachments"] # [{...}, ...]
get_email_raw(address_id)
Retrieve the raw RFC 822 email source.
raw = client.get_email_raw("abc123xyz789def456")
puts raw # Complete email with headers
download_attachment(address_id, index)
Download an attachment by zero-based index. Returns the raw content.
data = client.download_attachment("abc123xyz789def456", 0)
File.write("invoice.pdf", data)
wait_for_email(address_id, timeout:, poll_interval:)
Poll until an email arrives, with exponential backoff.
| Parameter | Type | Default | Description |
|---|---|---|---|
timeout: | Integer | 60 | Max seconds to wait. |
poll_interval: | Integer | 2 | Initial polling interval. |
Raises: OneShot::TimeoutError on timeout. OneShot::ExpiredError if the address expires.
email = client.wait_for_email(addr["id"], timeout: 30)
puts email["subject"]
send(to:, subject:, text_body:, html_body:, attachments:, ttl:, label:)
Send a one-shot email from a temporary address.
result = client.send(
to: "intake@myapp.com",
subject: "Test invoice",
text_body: "Please process this invoice.",
attachments: [
{
filename: "invoice.pdf",
content_type: "application/pdf",
content_base64: Base64.strict_encode64(File.read("invoice.pdf"))
}
],
label: "invoice-test"
)
puts result["address"] # "def456@out.oneshotemail.com"
list(status:, label:, mode:, limit:, cursor:)
List addresses with optional filtering.
addresses = client.list(status: "waiting", label: "ci-run-abc", limit: 10)
addresses.each { |addr| puts "#{addr['id']}: #{addr['status']}" }
delete(address_id)
Delete an address immediately.
client.delete("abc123xyz789def456")
delete_by_label(label)
Bulk-delete all addresses with the given label.
client.delete_by_label("ci-run-abc123")
account
Get account details and usage.
acct = client.account
puts "Plan: #{acct['plan']}"
puts "Receive: #{acct['usage']['receive']['used']}/#{acct['usage']['receive']['limit']}"
health
Check API health.
h = client.health
puts "Status: #{h['status']}"
Error handling
| Exception | HTTP Status | When |
|---|---|---|
OneShot::UnauthorizedError | 401 | Invalid or missing API key. |
OneShot::QuotaExceededError | 402 | Quota and credits exhausted. |
OneShot::NotFoundError | 404 | Address not found or no email yet. |
OneShot::ExpiredError | 410 | Address expired. |
OneShot::RateLimitedError | 429 | Rate limit exceeded. |
OneShot::TimeoutError | N/A | wait_for_email timed out. |
OneShot::Error | Any | Base class for all errors. |
begin
email = client.wait_for_email(addr["id"], timeout: 30)
rescue OneShot::TimeoutError
puts "Email did not arrive in time"
rescue OneShot::ExpiredError
puts "Address expired before email arrived"
rescue OneShot::QuotaExceededError
puts "Quota exceeded -- upgrade your plan"
end
Cucumber integration
This is the flagship integration. Cucumber was born in the Ruby world, and OneShotMail is built for BDD testing.
Directory structure
features/
signup.feature
steps/
signup_steps.rb
support/
env.rb
oneshot_helper.rb
Gemfile
Gemfile
source "https://rubygems.org"
gem "cucumber"
gem "oneshot-mail"
gem "rspec-expectations" # for should/expect matchers in steps
features/support/env.rb
require "oneshot"
require_relative "oneshot_helper"
# Create a shared client for the test run
ONESHOT_CLIENT = OneShot::Client.new(api_key: ENV.fetch("ONESHOT_API_KEY"))
RUN_ID = "cucumber-#{SecureRandom.hex(4)}"
# Clean up all addresses after the suite
at_exit do
ONESHOT_CLIENT.delete_by_label(RUN_ID)
end
features/support/oneshot_helper.rb
module OneShotHelper
def create_email_address(label_suffix = "")
label = "#{RUN_ID}-#{label_suffix}".sub(/-$/, "")
addr = ONESHOT_CLIENT.create(ttl: 300, label: label)
addr
end
def wait_for_email_at(address_id, timeout: 30)
ONESHOT_CLIENT.wait_for_email(address_id, timeout: timeout)
end
end
World(OneShotHelper)
features/signup.feature
Feature: User signup
As a new user
I want to sign up for an account
So that I can use the application
Scenario: Successful signup sends a verification email
Given I have a temporary email address
When I sign up with that email address
Then I should receive a verification email
And the email subject should contain "Verify your account"
And the email should contain a verification link
Scenario: Signup with an existing email shows an error
Given I have a temporary email address
And that email address is already registered
When I sign up with that email address
Then I should see an error message "Email already registered"
features/steps/signup_steps.rb
Given("I have a temporary email address") do
@address = create_email_address("signup")
@email_addr = @address["address"]
end
Given("that email address is already registered") do
# Use your app's API or test helper to create the user
MyApp::TestHelper.create_user(email: @email_addr)
end
When("I sign up with that email address") do
@response = MyApp::API.post("/signup", {
email: @email_addr,
password: "SecureP@ss1",
name: "Test User"
})
end
Then("I should receive a verification email") do
@email = wait_for_email_at(@address["id"], timeout: 30)
expect(@email).not_to be_nil
end
Then("the email subject should contain {string}") do |text|
expect(@email["subject"]).to include(text)
end
Then("the email should contain a verification link") do
body = @email["text_body"] || @email["html_body"]
@verification_link = body[%r{https?://\S+/verify\S*}]
expect(@verification_link).not_to be_nil
end
Then("I should see an error message {string}") do |message|
expect(@response.body).to include(message)
end
Running Cucumber
bundle install
export ONESHOT_API_KEY="osm_live_your_key"
bundle exec cucumber
RSpec integration
spec/spec_helper.rb
require "oneshot"
RSpec.configure do |config|
config.before(:suite) do
@oneshot_client = OneShot::Client.new(api_key: ENV.fetch("ONESHOT_API_KEY"))
@run_label = "rspec-#{SecureRandom.hex(4)}"
end
config.after(:suite) do
@oneshot_client&.delete_by_label(@run_label) rescue nil
end
end
# Shared context for email tests
RSpec.shared_context "with temporary email" do
let(:oneshot_client) { OneShot::Client.new(api_key: ENV.fetch("ONESHOT_API_KEY")) }
let(:run_label) { "rspec-#{SecureRandom.hex(4)}" }
let(:email_address) do
oneshot_client.create(ttl: 300, label: run_label)
end
after do
oneshot_client.delete(email_address["id"]) rescue nil
end
end
spec/signup_spec.rb
require "spec_helper"
RSpec.describe "User signup" do
include_context "with temporary email"
it "sends a verification email on signup" do
# Trigger signup
MyApp::API.post("/signup", {
email: email_address["address"],
password: "SecureP@ss1"
})
# Wait for the email
email = oneshot_client.wait_for_email(email_address["id"], timeout: 30)
expect(email["subject"]).to include("Verify your account")
expect(email["text_body"]).to include("Click")
end
it "includes the user's name in the verification email" do
MyApp::API.post("/signup", {
email: email_address["address"],
password: "SecureP@ss1",
name: "Alice"
})
email = oneshot_client.wait_for_email(email_address["id"], timeout: 30)
expect(email["text_body"]).to include("Alice")
end
end
Running RSpec
bundle install
export ONESHOT_API_KEY="osm_live_your_key"
bundle exec rspec