Documentation

Ruby SDK

Ruby 3.0+
Bundler

Send emails with Ruby using the official Laneful Ruby SDK. Built for modern Ruby applications with comprehensive features and type safety.

Full Feature Support

Templates, attachments, tracking, webhooks

Modern Ruby

Ruby 3.0+ with modern syntax

Easy Integration

Simple API with comprehensive examples

Prerequisites

To get the most out of this guide, you'll need:

  • • Ruby 3.0 or higher
  • • Bundler (for dependency management)
  • • A Laneful account with API key
  • • Verified domain for sending emails

Installation

Bundler

Add the following to your Gemfile:

gem 'laneful-ruby'

Then run:

bundle install

Quick Start

Send your first email in minutes:

Send Simple Text Email

require 'laneful'

# Create client
client = Laneful::Client.new(
  'https://your-endpoint.send.laneful.net',
  'your-auth-token'
)

# Create email
email = Laneful::Email::Builder.new
  .from(Laneful::Address.new('sender@example.com', 'Your Name'))
  .to(Laneful::Address.new('recipient@example.com', 'Recipient Name'))
  .subject('Hello from Laneful!')
  .text_content('This is a simple test email sent using the Laneful Ruby SDK.')
  .build

# Send email
begin
  response = client.send_email(email)
  puts "✓ Email sent successfully!"
  puts "Response: #{response}"
rescue Laneful::ValidationException => e
  puts "✗ Validation error: #{e.message}"
rescue Laneful::ApiException => e
  puts "✗ API error: #{e.message}"
  puts "Status code: #{e.status_code}"
rescue Laneful::HttpException => e
  puts "✗ HTTP error: #{e.message}"
rescue StandardError => e
  puts "✗ Unexpected error: #{e.message}"
end

Examples

Common use cases and patterns:

HTML Email with Tracking

# Create tracking settings
tracking = Laneful::TrackingSettings.new(
  opens: true, 
  clicks: true, 
  unsubscribes: false
)

email = Laneful::Email::Builder.new
  .from(Laneful::Address.new('sender@example.com'))
  .to(Laneful::Address.new('user@example.com'))
  .subject('HTML Email with Tracking')
  .html_content('<h1>Welcome!</h1><p>This is an <strong>HTML email</strong> with tracking enabled.</p>')
  .text_content('Welcome! This is an HTML email with tracking enabled.')
  .tracking(tracking)
  .tag('welcome-email')
  .build

response = client.send_email(email)

Template Email

email = Laneful::Email::Builder.new
  .from(Laneful::Address.new('sender@example.com'))
  .to(Laneful::Address.new('user@example.com'))
  .template_id('welcome-template')
  .template_data({
    'name' => 'John Doe',
    'company' => 'Acme Corporation',
    'activation_link' => 'https://example.com/activate'
  })
  .build

response = client.send_email(email)

Email with Attachments

# Create attachment from file
attachment = Laneful::Attachment.from_file('/path/to/document.pdf')

email = Laneful::Email::Builder.new
  .from(Laneful::Address.new('sender@example.com'))
  .to(Laneful::Address.new('user@example.com'))
  .subject('Document Attached')
  .text_content('Please find the document attached.')
  .attachment(attachment)
  .build

response = client.send_email(email)

Multiple Recipients with Reply-To

email = Laneful::Email::Builder.new
  .from(Laneful::Address.new('sender@example.com', 'Your Name'))
  .to(Laneful::Address.new('user1@example.com', 'User One'))
  .to(Laneful::Address.new('user2@example.com', 'User Two'))
  .cc(Laneful::Address.new('cc@example.com', 'CC Recipient'))
  .bcc(Laneful::Address.new('bcc@example.com', 'BCC Recipient'))
  .reply_to(Laneful::Address.new('reply@example.com', 'Reply To'))
  .subject('Email to Multiple Recipients')
  .text_content('This email is being sent to multiple recipients.')
  .build

response = client.send_email(email)

Scheduled Email

# Schedule for 24 hours from now
send_time = Time.now.to_i + (24 * 60 * 60)

email = Laneful::Email::Builder.new
  .from(Laneful::Address.new('sender@example.com'))
  .to(Laneful::Address.new('user@example.com'))
  .subject('Scheduled Email')
  .text_content('This email was scheduled.')
  .send_time(send_time)
  .build

response = client.send_email(email)

Batch Email Sending

emails = [
  Laneful::Email::Builder.new
    .from(Laneful::Address.new('sender@example.com'))
    .to(Laneful::Address.new('user1@example.com'))
    .subject('Email 1')
    .text_content('First email content.')
    .build,
  Laneful::Email::Builder.new
    .from(Laneful::Address.new('sender@example.com'))
    .to(Laneful::Address.new('user2@example.com'))
    .subject('Email 2')
    .text_content('Second email content.')
    .build
]

response = client.send_emails(emails)

Webhook Handler Example

require 'sinatra'
require 'json'
require 'laneful'

# Complete webhook handler implementation
class WebhookController
  def initialize(webhook_secret)
    @webhook_secret = webhook_secret
  end

  def handle_webhook(request)
    begin
      # Extract signature from headers
      signature = Laneful::WebhookVerifier.extract_signature_from_headers(request.env)
      if signature.nil?
        return [401, { 'Content-Type' => 'application/json' }, { error: 'Missing signature' }.to_json]
      end

      # Get raw payload
      payload = request.body.read

      # Verify signature
      unless Laneful::WebhookVerifier.verify_signature(@webhook_secret, payload, signature)
        return [401, { 'Content-Type' => 'application/json' }, { error: 'Invalid signature' }.to_json]
      end

      # Parse and validate payload
      webhook_data = Laneful::WebhookVerifier.parse_webhook_payload(payload)

      # Process events
      webhook_data[:events].each do |event|
        event_type = event['event']
        email = event['email']

        case event_type
        when 'delivery'
          puts "Email delivered to: #{email}"
        when 'open'
          puts "Email opened by: #{email}"
        when 'click'
          url = event['url'] || 'Unknown URL'
          puts "Link clicked by #{email}: #{url}"
        when 'bounce'
          is_hard = event['is_hard'] || false
          puts "Email bounced (#{is_hard ? 'hard' : 'soft'}) for: #{email}"
        end
      end

      [200, { 'Content-Type' => 'application/json' }, { status: 'success' }.to_json]

    rescue ArgumentError => e
      [400, { 'Content-Type' => 'application/json' }, { error: "Invalid payload: #{e.message}" }.to_json]
    rescue StandardError => e
      [500, { 'Content-Type' => 'application/json' }, { error: "Processing error: #{e.message}" }.to_json]
    end
  end
end

API Reference

Laneful::Client

Constructor

  • Laneful::Client.new(base_url, auth_token, timeout: 30) - Create a new client instance

Methods

  • send_email(email) - Send a single email
  • send_emails(emails) - Send multiple emails

Laneful::Email::Builder

Required Fields

  • from(address) - Sender address

Optional Fields

  • to(address) - Recipient addresses
  • cc(address) - CC addresses
  • bcc(address) - BCC addresses
  • subject(subject) - Email subject
  • text_content(content) - Plain text content
  • html_content(content) - HTML content
  • template_id(id) - Template ID
  • template_data(data) - Template data
  • attachment(attachment) - File attachments
  • headers(headers) - Custom headers
  • reply_to(address) - Reply-to address
  • send_time(time) - Scheduled send time (Unix timestamp)
  • webhook_data(data) - Webhook data
  • tag(tag) - Email tag for categorization
  • tracking(tracking) - Tracking settings

Utility Classes

  • Laneful::Address.new(email, name = nil) - Email address with optional name
  • Laneful::Attachment.from_file(file_path) - Create attachment from file
  • Laneful::Attachment.new(filename, content_type, content) - Create attachment from raw data
  • Laneful::TrackingSettings.new(opens: false, clicks: false, unsubscribes: false) - Email tracking configuration

Laneful::WebhookVerifier

Signature Verification

  • verify_signature(secret, payload, signature) - Verifies webhook signature (supports sha256= prefix)
  • generate_signature(secret, payload, include_prefix: false) - Generates signature for payload

Payload Processing

  • parse_webhook_payload(payload) - Parse and validate webhook payload structure
  • signature_header_name - Get the correct header name for webhook signatures
  • extract_signature_from_headers(headers) - Extract signature from HTTP headers

WebhookData

  • is_batch - Returns true if payload contains multiple events
  • events - Returns array of parsed events

Error Handling

Comprehensive error handling with specific exception types:

begin
  response = client.send_email(email)
  puts "✓ Email sent successfully!"
  puts "Response: #{response}"
rescue Laneful::ValidationException => e
  # Invalid input data
  puts "✗ Validation error: #{e.message}"
  puts "Please check your email configuration"
rescue Laneful::ApiException => e
  # API returned an error
  puts "✗ API error: #{e.message}"
  puts "  Status code: #{e.status_code}"
  puts "  Error message: #{e.error_message}"
  puts "Please check your API credentials and endpoint"
rescue Laneful::HttpException => e
  # Network or HTTP-level error
  puts "✗ HTTP error: #{e.message}"
  puts "  Status code: #{e.status_code}"
  puts "Please check your network connection and endpoint URL"
rescue StandardError => e
  # Other unexpected errors
  puts "✗ Unexpected error: #{e.message}"
  puts e.backtrace
end

Exception Types

  • Laneful::ValidationException - Input validation fails
  • Laneful::ApiException - API returns error response
    Methods: status_code, error_message
  • Laneful::HttpException - HTTP communication fails
    Methods: status_code
  • Laneful::LanefulException - Base exception class

Best Practices

  • • Always wrap API calls in begin-rescue
  • • Handle specific exception types first
  • • Log errors with context information
  • • Implement retry logic for transient failures

Webhook Handling

Comprehensive webhook handling with signature verification, payload parsing, and validation:

Basic Signature Verification

# In your webhook handler
payload = request.body.read
signature = request.headers['x-webhook-signature']
secret = 'your-webhook-secret'

if Laneful::WebhookVerifier.verify_signature(secret, payload, signature)
  # Process webhook data
  webhook_data = Laneful::WebhookVerifier.parse_webhook_payload(payload)
  # Handle webhook events
else
  # Invalid signature
  head :unauthorized
end

Advanced Webhook Processing

# Complete webhook verification and processing workflow
begin
  # Step 1: Get raw payload
  payload = request.body.read
  
  # Step 2: Extract signature from headers (supports multiple formats)
  signature = Laneful::WebhookVerifier.extract_signature_from_headers(request.env)
  
  # Step 3: Verify signature (supports sha256= prefix)
  unless signature && Laneful::WebhookVerifier.verify_signature(webhook_secret, payload, signature)
    raise StandardError, "Invalid webhook signature"
  end
  
  # Step 4: Parse and validate payload structure
  webhook_data = Laneful::WebhookVerifier.parse_webhook_payload(payload)
  
  # Step 5: Process events (handles both batch and single event formats)
  webhook_data[:events].each do |event|
    event_type = event['event']
    email = event['email']
    
    case event_type
    when 'delivery'
      handle_delivery_event(event)
    when 'open'
      handle_open_event(event)
    when 'click'
      handle_click_event(event)
    when 'bounce'
      handle_bounce_event(event)
    when 'drop'
      handle_drop_event(event)
    when 'spam_complaint'
      handle_spam_complaint_event(event)
    when 'unsubscribe'
      handle_unsubscribe_event(event)
    end
  end
  
rescue ArgumentError => e
  # Payload validation error
  status 400
  { error: "Invalid payload: #{e.message}" }.to_json
rescue StandardError => e
  # Other errors
  status 401
  { error: e.message }.to_json
end

Batch Mode Support

webhook_data = Laneful::WebhookVerifier.parse_webhook_payload(payload)

if webhook_data[:is_batch]
  # Processing multiple events in batch mode
  puts "Processing #{webhook_data[:events].length} events in batch"
else
  # Processing single event
  puts "Processing single event"
end

# Process all events
webhook_data[:events].each do |event|
  process_event(event)
end

Supported Webhook Events

Delivery Events

  • delivery - Email delivered successfully
  • bounce - Email bounced (hard or soft)
  • drop - Email dropped (spam, invalid, etc.)
  • spam_complaint - Recipient marked email as spam

Engagement Events

  • open - Email opened by recipient
  • click - Link clicked in email
  • unsubscribe - Recipient unsubscribed

Webhook Features

Security

  • • HMAC-SHA256 signature verification
  • • Support for sha256= prefix
  • • Constant-time comparison (timing attack protection)
  • • Multiple header format support

Validation

  • • JSON payload structure validation
  • • Required field validation
  • • Event type validation
  • • Email format validation
  • • UUID format validation for lane_id

Ready to Get Started?

Start sending emails with Ruby in minutes. Check out the examples and integrate with your application.