{"id":28411859,"url":"https://github.com/usepoodle/poodle-ruby","last_synced_at":"2025-08-05T10:16:57.529Z","repository":{"id":295573891,"uuid":"990339800","full_name":"usepoodle/poodle-ruby","owner":"usepoodle","description":"Poodle Ruby SDK","archived":false,"fork":false,"pushed_at":"2025-05-30T10:03:21.000Z","size":67,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-18T09:18:43.088Z","etag":null,"topics":["customer-communication","customer-communications","email","email-api","emails","marketing-email","marketing-emails","ruby","ruby-gem","ruby-on-rails","sinatra","transactional-email","transactional-emails"],"latest_commit_sha":null,"homepage":"https://usepoodle.com","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/usepoodle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-26T01:06:48.000Z","updated_at":"2025-05-30T10:03:25.000Z","dependencies_parsed_at":"2025-06-02T19:28:08.213Z","dependency_job_id":"1d864869-06aa-4434-9bbd-37b9912aa68f","html_url":"https://github.com/usepoodle/poodle-ruby","commit_stats":null,"previous_names":["usepoodle/poodle-ruby"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/usepoodle/poodle-ruby","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usepoodle%2Fpoodle-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usepoodle%2Fpoodle-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usepoodle%2Fpoodle-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usepoodle%2Fpoodle-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/usepoodle","download_url":"https://codeload.github.com/usepoodle/poodle-ruby/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usepoodle%2Fpoodle-ruby/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261628288,"owners_count":23186793,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["customer-communication","customer-communications","email","email-api","emails","marketing-email","marketing-emails","ruby","ruby-gem","ruby-on-rails","sinatra","transactional-email","transactional-emails"],"created_at":"2025-06-02T19:16:14.070Z","updated_at":"2025-08-05T10:16:57.516Z","avatar_url":"https://github.com/usepoodle.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Poodle Ruby SDK\n\n[![Gem Version](https://badge.fury.io/rb/poodle-ruby.svg)](https://rubygems.org/gems/poodle-ruby)\n[![Build Status](https://github.com/usepoodle/poodle-ruby/workflows/CI/badge.svg)](https://github.com/usepoodle/poodle-ruby/actions)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/usepoodle/poodle-ruby/blob/main/LICENSE)\n\nRuby SDK for the Poodle's email sending API.\n\n## Table of Contents\n\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Usage Examples](#usage-examples)\n- [API Reference](#api-reference)\n- [Error Types](#error-types)\n- [Development](#development)\n- [Contributing](#contributing)\n- [License](#license)\n- [Support](#support)\n\n## Features\n\n- 🚀 **Simple API** - Send emails with just a few lines of code\n- 🔒 **Type Safe** - Comprehensive validation and error handling\n- 🌐 **Environment Support** - Easy configuration via environment variables\n- 📝 **Rich Content** - Support for HTML, plain text, and multipart emails\n- 🔄 **Retry Logic** - Built-in support for handling rate limits and network issues\n- 🧪 **Test Support** - Comprehensive testing utilities and mocks\n- 📚 **Well Documented** - Comprehensive documentation and examples\n- 🎯 **Ruby 3.0+** - Modern Ruby support with keyword arguments\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'poodle-ruby'\n```\n\nAnd then execute:\n\n```bash\nbundle install\n```\n\nOr install it yourself as:\n\n```bash\ngem install poodle-ruby\n```\n\n## Quick Start\n\n```ruby\nrequire 'poodle'\n\n# Initialize the client\nclient = Poodle::Client.new(api_key: 'your_api_key')\n\n# Send an email\nresponse = client.send(\n  from: 'sender@example.com',\n  to: 'recipient@example.com',\n  subject: 'Hello from Poodle!',\n  html: '\u003ch1\u003eHello World!\u003c/h1\u003e\u003cp\u003eThis email was sent using Poodle.\u003c/p\u003e'\n)\n\nif response.success?\n  puts \"Email sent successfully!\"\nelse\n  puts \"Failed to send email: #{response.message}\"\nend\n```\n\n## Configuration\n\n### API Key\n\nSet your API key in one of these ways:\n\n```ruby\n# 1. Pass directly to client\nclient = Poodle::Client.new(api_key: 'your_api_key')\n\n# 2. Use environment variable\nENV['POODLE_API_KEY'] = 'your_api_key'\nclient = Poodle::Client.new\n\n# 3. Use configuration object\nconfig = Poodle::Configuration.new(\n  api_key: 'your_api_key',\n  timeout: 30,\n  debug: true\n)\nclient = Poodle::Client.new(config)\n```\n\n### Environment Variables\n\n| Variable                 | Description                   | Default                     |\n| ------------------------ | ----------------------------- | --------------------------- |\n| `POODLE_API_KEY`         | Your Poodle API key           | Required                    |\n| `POODLE_BASE_URL`        | API base URL                  | `https://api.usepoodle.com` |\n| `POODLE_TIMEOUT`         | Request timeout in seconds    | `30`                        |\n| `POODLE_CONNECT_TIMEOUT` | Connection timeout in seconds | `10`                        |\n| `POODLE_DEBUG`           | Enable debug logging          | `false`                     |\n\n## Usage Examples\n\n### Basic Email Sending\n\n```ruby\n# HTML email\nresponse = client.send_html(\n  from: 'newsletter@example.com',\n  to: 'subscriber@example.com',\n  subject: 'Weekly Newsletter',\n  html: '\u003ch1\u003eNewsletter\u003c/h1\u003e\u003cp\u003eYour weekly update...\u003c/p\u003e'\n)\n\n# Plain text email\nresponse = client.send_text(\n  from: 'notifications@example.com',\n  to: 'user@example.com',\n  subject: 'Account Update',\n  text: 'Your account has been updated successfully.'\n)\n\n# Multipart email (HTML + Text)\nresponse = client.send(\n  from: 'support@example.com',\n  to: 'customer@example.com',\n  subject: 'Welcome!',\n  html: '\u003ch1\u003eWelcome!\u003c/h1\u003e\u003cp\u003eThanks for joining us.\u003c/p\u003e',\n  text: 'Welcome! Thanks for joining us.'\n)\n```\n\n### Using Email Objects\n\n```ruby\n# Create an Email object for reusability and validation\nemail = Poodle::Email.new(\n  from: 'sender@example.com',\n  to: 'recipient@example.com',\n  subject: 'Important Update',\n  html: '\u003ch1\u003eUpdate\u003c/h1\u003e\u003cp\u003ePlease read this important update.\u003c/p\u003e',\n  text: 'Update: Please read this important update.'\n)\n\n# Check email properties\nputs \"Multipart email: #{email.multipart?}\"\nputs \"Content size: #{email.content_size} bytes\"\n\n# Send the email\nresponse = client.send_email(email)\n```\n\n### Multipart Emails (HTML + Text)\n\n```ruby\n# Send emails with both HTML and text content for maximum compatibility\nresponse = client.send(\n  from: 'newsletter@example.com',\n  to: 'subscriber@example.com',\n  subject: 'Weekly Newsletter',\n  html: '\u003ch1\u003eNewsletter\u003c/h1\u003e\u003cp\u003eThis week\\'s updates...\u003c/p\u003e',\n  text: 'Newsletter\\n\\nThis week\\'s updates...'\n)\n```\n\n### Rails Integration\n\nThe Poodle SDK provides seamless Rails integration with automatic configuration and helpful rake tasks.\n\n#### Installation\n\nAdd to your Rails application's Gemfile:\n\n```ruby\ngem 'poodle-ruby'\n```\n\n#### Configuration\n\nCreate an initializer or let Poodle auto-configure:\n\n```ruby\n# config/initializers/poodle.rb\nPoodle::Rails.configure do |config|\n  config.api_key = Rails.application.credentials.poodle_api_key\n  config.debug = Rails.env.development?\nend\n```\n\nOr use environment variables:\n\n```bash\n# .env or environment\nPOODLE_API_KEY=your_api_key_here\n```\n\n#### Usage in Controllers\n\n```ruby\nclass NotificationController \u003c ApplicationController\n  def send_welcome_email\n    response = Poodle::Rails.client.send(\n      from: \"welcome@example.com\",\n      to: params[:email],\n      subject: \"Welcome!\",\n      html: render_to_string(\"welcome_email\")\n    )\n\n    if response.success?\n      render json: { status: \"sent\" }\n    else\n      render json: { error: response.message }, status: :unprocessable_entity\n    end\n  end\nend\n```\n\n#### Rake Tasks\n\n```bash\n# Check configuration\nrake poodle:config\n\n# Test connection\nrake poodle:test\n\n# Send test email\nrake poodle:send_test[recipient@example.com]\n\n# Generate initializer\nrake poodle:install\n```\n\n### Testing\n\nThe SDK includes comprehensive testing utilities for easy testing in your applications.\n\n#### RSpec Integration\n\n```ruby\n# spec/spec_helper.rb or spec/rails_helper.rb\nrequire 'poodle'\n\nRSpec.configure do |config|\n  config.include Poodle::TestHelpers\n\n  config.before(:each) do\n    Poodle.test_mode!\n  end\n\n  config.after(:each) do\n    Poodle.clear_deliveries\n  end\nend\n```\n\n#### Testing Email Sending\n\n```ruby\nit \"sends welcome email\" do\n  expect {\n    UserMailer.send_welcome(user)\n  }.to change { Poodle.deliveries.count }.by(1)\n\n  email = Poodle.last_delivery\n  expect(email[:to]).to eq(user.email)\n  expect(email[:subject]).to include(\"Welcome\")\n  expect(email[:html]).to include(user.name)\nend\n\nit \"sends notification emails\" do\n  service.send_notifications\n\n  assert_email_sent(3)\n  assert_email_sent_to(\"admin@example.com\")\n  assert_email_sent_with_subject(\"Alert\")\nend\n```\n\n### Error Handling\n\n```ruby\nbegin\n  response = client.send(email_data)\n  puts \"Email sent!\" if response.success?\nrescue Poodle::ValidationError =\u003e e\n  puts \"Validation failed: #{e.message}\"\n  e.errors.each do |field, messages|\n    puts \"#{field}: #{messages.join(', ')}\"\n  end\nrescue Poodle::AuthenticationError =\u003e e\n  puts \"Authentication failed: #{e.message}\"\nrescue Poodle::RateLimitError =\u003e e\n  puts \"Rate limited. Retry after: #{e.retry_after} seconds\"\nrescue Poodle::PaymentError =\u003e e\n  puts \"Payment required: #{e.message}\"\n  puts \"Upgrade at: #{e.upgrade_url}\"\nrescue Poodle::ForbiddenError =\u003e e\n  puts \"Access forbidden: #{e.message}\"\nrescue Poodle::NetworkError =\u003e e\n  puts \"Network error: #{e.message}\"\nrescue Poodle::ServerError =\u003e e\n  puts \"Server error: #{e.message}\"\nrescue Poodle::Error =\u003e e\n  puts \"Poodle error: #{e.message}\"\nend\n```\n\n### Retry Logic\n\n```ruby\ndef send_with_retry(client, email_data, max_retries: 3)\n  retries = 0\n\n  begin\n    client.send(email_data)\n  rescue Poodle::RateLimitError =\u003e e\n    if retries \u003c max_retries \u0026\u0026 e.retry_after\n      retries += 1\n      sleep(e.retry_after)\n      retry\n    else\n      raise\n    end\n  rescue Poodle::NetworkError, Poodle::ServerError =\u003e e\n    if retries \u003c max_retries\n      retries += 1\n      sleep(2 ** retries) # Exponential backoff\n      retry\n    else\n      raise\n    end\n  end\nend\n```\n\n## API Reference\n\n### Client\n\n#### `Poodle::Client.new(config_or_api_key, **options)`\n\nCreates a new Poodle client.\n\n**Parameters:**\n\n- `config_or_api_key` - Configuration object, API key string, or nil\n- `**options` - Additional options (base_url, timeout, debug, etc.)\n\n#### `client.send(from:, to:, subject:, html: nil, text: nil)`\n\nSends an email with the specified parameters.\n\n#### `client.send_email(email)`\n\nSends an Email object.\n\n#### `client.send_html(from:, to:, subject:, html:)`\n\nSends an HTML-only email.\n\n#### `client.send_text(from:, to:, subject:, text:)`\n\nSends a text-only email.\n\n### Email\n\n#### `Poodle::Email.new(from:, to:, subject:, html: nil, text: nil)`\n\nCreates a new Email object with validation.\n\n**Methods:**\n\n- `#html?` - Returns true if HTML content is present\n- `#text?` - Returns true if text content is present\n- `#multipart?` - Returns true if both HTML and text are present\n- `#content_size` - Returns total content size in bytes\n- `#to_h` - Converts to hash for API requests\n\n### EmailResponse\n\n#### Properties\n\n- `#success?` - Returns true if email was successfully queued\n- `#failed?` - Returns true if email sending failed\n- `#message` - Response message from API\n- `#data` - Additional response data\n\n### Configuration\n\n#### `Poodle::Configuration.new(**options)`\n\nCreates a new configuration object.\n\n**Options:**\n\n- `api_key` - Your Poodle API key\n- `base_url` - API base URL\n- `timeout` - Request timeout in seconds\n- `connect_timeout` - Connection timeout in seconds\n- `debug` - Enable debug logging\n- `http_options` - Additional HTTP client options\n\n## Error Types\n\n| Error Class                   | Description              | HTTP Status |\n| ----------------------------- | ------------------------ | ----------- |\n| `Poodle::ValidationError`     | Invalid request data     | 400, 422    |\n| `Poodle::AuthenticationError` | Invalid API key          | 401         |\n| `Poodle::PaymentError`        | Payment required         | 402         |\n| `Poodle::ForbiddenError`      | Access forbidden         | 403         |\n| `Poodle::RateLimitError`      | Rate limit exceeded      | 429         |\n| `Poodle::ServerError`         | Server error             | 5xx         |\n| `Poodle::NetworkError`        | Network/connection error | Various     |\n\nAll errors inherit from `Poodle::Error` which provides:\n\n- `#message` - Error message\n- `#context` - Additional error context\n- `#status_code` - HTTP status code (if applicable)\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nContributions are welcome! Please read our [Contributing Guide](https://github.com/usepoodle/poodle-ruby/blob/main/CONTRIBUTING.md) for details on the process for submitting pull requests and our [Code of Conduct](https://github.com/usepoodle/poodle-ruby/blob/main/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusepoodle%2Fpoodle-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fusepoodle%2Fpoodle-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusepoodle%2Fpoodle-ruby/lists"}