Integration

Send emails from Ruby on Rails with Postkit

Send transactional emails from Rails controllers or Active Job workers using Postkit's REST API with Net::HTTP or Faraday.

1. Set your API key

# config/credentials.yml.enc (or .env)
POSTKIT_API_KEY: pk_live_...

2. Send an email

ruby
# app/controllers/emails_controller.rb
class EmailsController < ApplicationController
  def send_welcome
    uri = URI("https://api.postkit.eu/v1/emails")
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(uri)
    request["Authorization"] = "Bearer #{ENV['POSTKIT_API_KEY']}"
    request["Content-Type"] = "application/json"
    request.body = {
      from: "hello@yourapp.eu",
      to: params[:email],
      subject: "Welcome aboard!",
      html: "<h1>Welcome, #{params[:name]}!</h1>"
    }.to_json

    response = http.request(request)
    render json: JSON.parse(response.body)
  end
end

3. Handle webhooks

Postkit sends delivery events (sent, delivered, bounced, opened, clicked) via HMAC-SHA256 signed webhooks following the Standard Webhooks specification.

ruby
# app/controllers/webhooks_controller.rb
class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token

  def postkit
    body = request.raw_post
    msg_id = request.headers["webhook-id"] || ""
    timestamp = request.headers["webhook-timestamp"] || ""
    signature = request.headers["webhook-signature"] || ""

    secret_b64 = ENV["POSTKIT_WEBHOOK_SECRET"].sub("whsec_", "")
    secret = Base64.decode64(secret_b64)
    content = "#{msg_id}.#{timestamp}.#{body}"
    expected = Base64.encode64(
      OpenSSL::HMAC.digest("sha256", secret, content)
    ).strip

    valid = signature.split(" ").any? do |sig|
      Rack::Utils.secure_compare(sig.sub("v1,", ""), expected)
    end

    unless valid
      return render json: { error: "Invalid signature" }, status: :unauthorized
    end

    event = JSON.parse(body)
    Rails.logger.info "Postkit event: #{event['type']}"
    render json: { received: true }
  end
end

Start sending in under 5 minutes

Free plan. No credit card required.

Get Started Free