Official Sidemail.io Ruby library providing convenient access to the Sidemail API from Ruby applications.
- Ruby 2.6+
Using RubyGems:
gem install sidemailOr using Bundler:
bundle add sidemailFirst, the client needs to be configured with your project's API key, which you can find in the Sidemail Dashboard after you sign up.
require "sidemail"
# Initialize with API key
sm = Sidemail.new(api_key: "your-api-key")
# Or set environment variable SIDEMAIL_API_KEY
# sm = Sidemail.newresponse = sm.send_email(
toAddress: "user@email.com",
fromAddress: "you@example.com",
fromName: "Your App",
templateName: "Welcome",
templateProps: { foo: "bar" }
)
puts "Email sent! ID: #{response.id}"The response looks like:
{
"id": "5e858953daf20f3aac50a3da",
"status": "queued"
}Shortcut sm.send_email(...) calls sm.email.send(...) under the hood.
Explicit key:
require "sidemail"
sm = Sidemail.new(api_key: "your-api-key")Or if you set environment variable SIDEMAIL_API_KEY, then simply:
require "sidemail"
sm = Sidemail.new # reads SIDEMAIL_API_KEYrequire "sidemail"
sm = Sidemail.new(
api_key: "your-api-key",
base_url: "https://api.sidemail.io/v1", # override for testing/mocking
timeout: 10.0, # per-request timeout (seconds)
http_client: custom_http_client, # custom Net::HTTP client (proxies, retries, etc.)
)sm.send_email(
toAddress: "user@email.com",
fromAddress: "you@example.com",
fromName: "Your App",
templateName: "Password reset",
templateProps: { resetUrl: "https://your.app/reset?token=123" }
)require "date"
# Schedule for 60 minutes from now
scheduled_iso = (Time.now + 60 * 60).utc.iso8601
sm.send_email(
toAddress: "user@email.com",
fromAddress: "your@startup.com",
fromName: "Startup name",
templateName: "Welcome",
templateProps: { firstName: "Patrik" },
scheduledAt: scheduled_iso
)sm.send_email(
toAddress: "user@email.com",
fromAddress: "your@startup.com",
fromName: "Startup name",
templateName: "Template with dynamic list",
templateProps: {
list: [
{ text: "Dynamic list" },
{ text: "allows you to generate email template content" },
{ text: "based on template props." }
]
}
)sm.send_email(
toAddress: "user@email.com",
fromAddress: "your@startup.com",
fromName: "Startup name",
subject: "Testing html only custom emails :)",
html: "<html><body><h1>Hello world! 👋</h1></body></html>"
)sm.send_email(
toAddress: "user@email.com",
fromAddress: "your@startup.com",
fromName: "Startup name",
subject: "Testing plain-text only custom emails :)",
text: "Hello world! 👋"
)The SDK raises Sidemail::Error for all errors. API errors include message, http_status, error_code, and more_info.
require "sidemail"
sm = Sidemail.new(api_key: "your-api-key")
begin
sm.send_email(
toAddress: "user@example.com",
fromAddress: "you@example.com",
subject: "Hello",
text: "Hello"
)
rescue Sidemail::Error => e
puts e.message
if e.http_status # API error
puts "#{e.http_status} #{e.error_code} #{e.more_info}"
end
endMost responses are wrapped in a Resource enabling attribute access while remaining hash-like.
- Methods return
Resourcewrappers (attribute + hash access); unwrap via.to_h. - Original JSON available via
.raw.
response = sm.email.get("email-id")
puts "#{response.email.id} #{response.email.status}"
puts response.email["id"] # hash-style
raw_json = response.raw # original JSON mapping
flat_hash = response.to_h # fully unwrapped hashrequire "sidemail"
file_content = File.read("invoice.pdf")
attachment = Sidemail.file_to_attachment("invoice.pdf", file_content)
sm.send_email(
toAddress: "user@email.com",
fromAddress: "you@example.com",
subject: "Invoice",
text: "Invoice attached.",
attachments: [attachment]
)List/search methods return a PaginatedResponse containing the first page in result.data. Iterate across all pages with auto_paginate.
result = sm.contacts.list(limit: 50)
result.auto_paginate.each do |contact|
puts contact.emailAddress
endSupported auto-paging methods:
sm.contacts.listsm.contacts.querysm.email.searchsm.messenger.list
Paginated (supports auto-pagination).
result = sm.email.search(
query: {
toAddress: "john.doe@example.com",
status: "delivered",
templateProps: { foo: "bar" }
},
limit: 50
)
puts "First page count: #{result.items.count}"
result.auto_paginate.each do |email|
puts "#{email.id} #{email.status}"
endresp = sm.email.get("SIDEMAIL_EMAIL_ID")
puts resp.emailOnly scheduled (future) emails can be deleted.
resp = sm.email.delete("SIDEMAIL_EMAIL_ID")
puts "Deleted: #{resp.deleted}"resp = sm.contacts.create_or_update(
emailAddress: "marry@lightning.com",
identifier: "123",
customProps: {
name: "Marry Lightning"
# ... more props ...
}
)
puts "Contact status: #{resp.status}"resp = sm.contacts.find("marry@lightning.com")
if resp.contact
puts "Found contact: #{resp.contact.emailAddress}"
endresult = sm.contacts.list(limit: 50)
puts "Has more: #{result.has_more}"
result.auto_paginate.each do |c|
puts c.emailAddress
endresult = sm.contacts.query(limit: 100, query: { "customProps.plan" => "pro" })
result.auto_paginate.each do |c|
puts c.emailAddress
endresp = sm.contacts.delete("marry@lightning.com")
puts respLinked projects are associated with the parent project of the API key used to initialize Sidemail. After creation, update the design to personalize templates.
project = sm.project.create(name: "Customer X linked project")
# Important! Save project.apiKey for later useupdated = sm.project.update(
name: "New name",
emailTemplateDesign: {
logo: {
sizeWidth: 50,
href: "https://example.com",
file: "PHN2ZyBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjIiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMTIgNS43MmMtMi42MjQtNC41MTctMTAtMy4xOTgtMTAgMi40NjEgMCAzLjcyNSA0LjM0NSA3LjcyNyA5LjMwMyAxMi41NC4xOTQuMTg5LjQ0Ni4yODMuNjk3LjI4M3MuNTAzLS4wOTQuNjk3LS4yODNjNC45NzctNC44MzEgOS4zMDMtOC44MTQgOS4zMDMtMTIuNTQgMC01LjY3OC03LjM5Ni02Ljk0NC0xMC0yLjQ2MXoiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==",
},
font: { name: "Acme" },
colors: { highlight: "#0000FF", isDarkModeEnabled: true },
unsubscribeText: "Darse de baja",
footerTextTransactional: "You're receiving these emails because you registered for Acme Inc."
}
)project = sm.project.get
puts "#{project.id} #{project.name}"resp = sm.project.delete
puts respresult = sm.messenger.list(limit: 20)
result.auto_paginate.each do |m|
puts "#{m.id} #{m.name}"
end
messenger = sm.messenger.get("messenger-id")
created = sm.messenger.create(subject: "My Messenger", markdown: "Broadcast message...")
updated = sm.messenger.update("messenger-id", name: "Updated name")
deleted = sm.messenger.delete("messenger-id")domains = sm.domains.list
domain = sm.domains.create(name: "example.com")
deleted = sm.domains.delete("domain-id")Visit Sidemail docs for more information.