├── .env_sample ├── .github └── workflows │ ├── pr-lint.yml │ └── test-and-deploy.yml ├── .gitignore ├── .rubocop.yml ├── .rubocop_todo.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── FIRST_TIMERS.md ├── Gemfile ├── LICENSE ├── Makefile ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── Rakefile ├── TROUBLESHOOTING.md ├── UPGRADE.md ├── USAGE.md ├── config.ru ├── examples ├── accesssettings │ └── accesssettings.rb ├── alerts │ └── alerts.rb ├── apikeys │ └── apikeys.rb ├── asm │ └── asm.rb ├── browsers │ └── browsers.rb ├── campaigns │ └── campaigns.rb ├── categories │ └── categories.rb ├── clients │ └── clients.rb ├── contactdb │ └── contactdb.rb ├── dataresidency │ └── setregion.rb ├── devices │ └── devices.rb ├── emailactivity │ └── emailactivity.rb ├── geo │ └── geo.rb ├── helpers │ ├── eventwebhook │ │ └── example.rb │ ├── mail │ │ └── example.rb │ ├── settings │ │ └── example.rb │ └── stats │ │ └── example.rb ├── ips │ └── ips.rb ├── mail │ └── mail.rb ├── mailboxproviders │ └── mailboxproviders.rb ├── mailsettings │ └── mailsettings.rb ├── partnersettings │ └── partnersettings.rb ├── scopes │ └── scopes.rb ├── senderauthentication │ └── senderauthentication.rb ├── senders │ └── senders.rb ├── stats │ └── stats.rb ├── subusers │ └── subusers.rb ├── suppression │ └── suppression.rb ├── templates │ └── templates.rb ├── trackingsettings │ └── trackingsettings.rb └── user │ └── user.rb ├── gemfiles ├── Sinatra_1.gemfile └── Sinatra_2.gemfile ├── lib ├── rack │ └── sendgrid_webhook_verification.rb ├── sendgrid-ruby.rb └── sendgrid │ ├── base_interface.rb │ ├── helpers │ ├── eventwebhook │ │ └── eventwebhook.rb │ ├── inbound │ │ ├── README.md │ │ ├── app.rb │ │ ├── config.yml │ │ ├── public │ │ │ └── index.html │ │ ├── sample_data │ │ │ ├── default_data.txt │ │ │ ├── raw_data.txt │ │ │ └── raw_data_with_attachments.txt │ │ └── send.rb │ ├── ip_management │ │ └── ip_management.rb │ ├── mail │ │ ├── README.md │ │ ├── asm.rb │ │ ├── attachment.rb │ │ ├── bcc_settings.rb │ │ ├── bypass_list_management.rb │ │ ├── category.rb │ │ ├── click_tracking.rb │ │ ├── content.rb │ │ ├── custom_arg.rb │ │ ├── email.rb │ │ ├── footer.rb │ │ ├── ganalytics.rb │ │ ├── header.rb │ │ ├── mail.rb │ │ ├── mail_settings.rb │ │ ├── open_tracking.rb │ │ ├── personalization.rb │ │ ├── section.rb │ │ ├── spam_check.rb │ │ ├── subscription_tracking.rb │ │ ├── substitution.rb │ │ └── tracking_settings.rb │ ├── permissions │ │ ├── scope.rb │ │ └── scopes.yml │ ├── settings │ │ ├── README.md │ │ ├── mail_settings_dto.rb │ │ ├── partner_settings_dto.rb │ │ ├── settings.rb │ │ ├── tracking_settings_dto.rb │ │ └── user_settings_dto.rb │ └── stats │ │ ├── email_stats.rb │ │ ├── metrics.rb │ │ └── stats_response.rb │ ├── sendgrid.rb │ ├── twilio_email.rb │ └── version.rb ├── mail_helper_v3.md ├── sendgrid-ruby.gemspec ├── spec ├── fixtures │ └── event_webhook.rb ├── rack │ └── sendgrid_webhook_verification_spec.rb ├── sendgrid │ ├── helpers │ │ ├── eventwebhook │ │ │ └── eventwebhook_spec.rb │ │ ├── ip_management │ │ │ └── ip_management_spec.rb │ │ ├── settings │ │ │ ├── mail_settings_dto_spec.rb │ │ │ ├── partner_settings_dto_spec.rb │ │ │ ├── settings_spec.rb │ │ │ ├── tracking_settings_dto_spec.rb │ │ │ └── user_settings_dto_spec.rb │ │ └── stats │ │ │ ├── email_stats_spec.rb │ │ │ ├── metrics_spec.rb │ │ │ └── stats_response_spec.rb │ ├── sendgrid_spec.rb │ └── twilio_email_spec.rb └── spec_helper.rb ├── static └── img │ ├── github-fork.png │ └── github-sign-up.png ├── test └── sendgrid │ ├── helpers │ └── mail │ │ ├── test_attachment.rb │ │ ├── test_category.rb │ │ ├── test_data_residency.rb │ │ ├── test_email.rb │ │ ├── test_mail.rb │ │ └── test_personalizations.rb │ ├── permissions │ └── test_scopes.rb │ └── test_sendgrid-ruby.rb ├── twilio_sendgrid_logo.png └── use-cases ├── README.md ├── domain-authentication.md ├── email-statistics.md ├── legacy-templates.md ├── personalizations.md ├── sms.md ├── transactional-templates.md ├── twilio-email.md └── twilio-setup.md /.env_sample: -------------------------------------------------------------------------------- 1 | export SENDGRID_API_KEY='' -------------------------------------------------------------------------------- /.github/workflows/pr-lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR 2 | on: 3 | pull_request_target: 4 | types: [ opened, edited, synchronize, reopened ] 5 | 6 | jobs: 7 | validate: 8 | name: Validate title 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: amannn/action-semantic-pull-request@v4 12 | with: 13 | types: chore docs fix feat test misc 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/test-and-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test and Deploy 2 | on: 3 | push: 4 | branches: [ '*' ] 5 | tags: [ '*' ] 6 | pull_request: 7 | branches: [ main ] 8 | schedule: 9 | # Run automatically at 8AM PST Monday-Friday 10 | - cron: '0 15 * * 1-5' 11 | workflow_dispatch: 12 | 13 | jobs: 14 | test: 15 | name: Test 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 20 18 | strategy: 19 | matrix: 20 | ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', 'jruby-9.2' ] 21 | env: 22 | version: ${{ format('ruby:{0}', matrix.ruby) }} 23 | DOCKER_LOGIN: ${{ secrets.DOCKER_USERNAME && secrets.DOCKER_AUTH_TOKEN }} 24 | steps: 25 | - name: Revise env version if necessary 26 | run: echo "version=jruby:9.2" >> $GITHUB_ENV 27 | if: ${{ matrix.ruby == 'jruby-9.2' }} 28 | 29 | - name: Checkout sendgrid-ruby 30 | uses: actions/checkout@v2 31 | with: 32 | fetch-depth: 0 33 | 34 | - name: Login to Docker Hub 35 | if: env.DOCKER_LOGIN 36 | uses: docker/login-action@v1 37 | with: 38 | username: ${{ secrets.DOCKER_USERNAME }} 39 | password: ${{ secrets.DOCKER_AUTH_TOKEN }} 40 | 41 | - name: Set up Ruby 42 | uses: ruby/setup-ruby@v1 43 | with: 44 | ruby-version: ${{ matrix.ruby }} 45 | bundler-cache: true 46 | 47 | - run: make install 48 | 49 | - name: Set up linter 50 | run: bundle add rubocop --version "~> 1.24.1" --group "development" --skip-install 51 | if: ${{ matrix.ruby != '2.4' }} 52 | 53 | - run: bundle install --with development 54 | 55 | - name: Run linter 56 | run: bundle exec rubocop 57 | if: ${{ matrix.ruby != '2.4' }} 58 | 59 | - name: Run tests 60 | run: make test-docker 61 | 62 | deploy: 63 | name: Deploy 64 | if: success() && github.ref_type == 'tag' 65 | needs: [ test ] 66 | runs-on: ubuntu-latest 67 | steps: 68 | - name: Checkout sendgrid-ruby 69 | uses: actions/checkout@v2 70 | with: 71 | fetch-depth: 0 72 | 73 | - name: Set up Ruby 74 | uses: ruby/setup-ruby@v1 75 | with: 76 | ruby-version: 3.1 77 | bundler-cache: true 78 | 79 | - run: make install 80 | 81 | - name: Create GitHub Release 82 | uses: sendgrid/dx-automator/actions/release@main 83 | with: 84 | footer: '**[RubyGems](https://rubygems.org/gems/sendgrid-ruby/versions/${version})**' 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | 88 | - name: Publish to Rubygems 89 | env: 90 | GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }} 91 | run: | 92 | mkdir -p $HOME/.gem 93 | touch $HOME/.gem/credentials 94 | chmod 0600 $HOME/.gem/credentials 95 | printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials 96 | gem build *.gemspec 97 | gem push *.gem 98 | 99 | - name: Submit metric to Datadog 100 | uses: sendgrid/dx-automator/actions/datadog-release-metric@main 101 | env: 102 | DD_API_KEY: ${{ secrets.DATADOG_API_KEY }} 103 | 104 | notify-on-failure: 105 | name: Slack notify on failure 106 | if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag') 107 | needs: [ test, deploy ] 108 | runs-on: ubuntu-latest 109 | steps: 110 | - uses: rtCamp/action-slack-notify@v2 111 | env: 112 | SLACK_COLOR: failure 113 | SLACK_ICON_EMOJI: ':github:' 114 | SLACK_MESSAGE: ${{ format('Test *{0}*, Deploy *{1}*, {2}/{3}/actions/runs/{4}', needs.test.result, needs.deploy.result, github.server_url, github.repository, github.run_id) }} 115 | SLACK_TITLE: Action Failure - ${{ github.repository }} 116 | SLACK_USERNAME: GitHub Actions 117 | SLACK_MSG_AUTHOR: twilio-dx 118 | SLACK_FOOTER: Posted automatically using GitHub Actions 119 | SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} 120 | MSG_MINIMAL: true 121 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### Ruby ### 4 | bin 5 | *.gem 6 | *.rbc 7 | /.config 8 | /coverage/ 9 | /InstalledFiles 10 | /pkg/ 11 | /spec/reports/ 12 | /test/tmp/ 13 | /test/version_tmp/ 14 | /tmp/ 15 | .env 16 | test.rb 17 | 18 | ## Specific to RubyMotion: 19 | .dat* 20 | .repl_history 21 | build/ 22 | 23 | ## Documentation cache and generated files: 24 | /.yardoc/ 25 | /_yardoc/ 26 | /doc/ 27 | /rdoc/ 28 | 29 | ## Environment normalisation: 30 | /.bundle/ 31 | /vendor/bundle 32 | /lib/bundler/man/ 33 | 34 | # for a library or gem, you might want to ignore these files since the code is 35 | # intended to run in multiple environments; otherwise, check them in: 36 | Gemfile.lock 37 | .ruby-version 38 | .ruby-gemset 39 | 40 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 41 | .rvmrc 42 | 43 | prism* 44 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | Style/StringLiterals: 4 | Enabled: false 5 | 6 | Metrics/BlockLength: 7 | Exclude: 8 | - 'spec/**/*' 9 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2022-01-25 23:45:43 UTC using RuboCop version 1.22.2. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 1 10 | # Cop supports --auto-correct. 11 | # Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include. 12 | # Include: **/*.gemfile, **/Gemfile, **/gems.rb 13 | Bundler/OrderedGems: 14 | Exclude: 15 | - 'Gemfile' 16 | 17 | # Offense count: 1 18 | # Configuration parameters: Include. 19 | # Include: **/*.gemspec 20 | Gemspec/RequiredRubyVersion: 21 | Exclude: 22 | - 'sendgrid-ruby.gemspec' 23 | 24 | # Offense count: 1 25 | # Cop supports --auto-correct. 26 | # Configuration parameters: EnforcedStyle. 27 | # SupportedStyles: final_newline, final_blank_line 28 | Layout/TrailingEmptyLines: 29 | Exclude: 30 | - 'Gemfile' 31 | 32 | # Offense count: 24 33 | Lint/UselessAssignment: 34 | Exclude: 35 | - 'examples/scopes/scopes.rb' 36 | - 'spec/rack/sendgrid_webhook_verification_spec.rb' 37 | 38 | # Offense count: 10 39 | # Configuration parameters: IgnoredMethods, CountRepeatedAttributes. 40 | Metrics/AbcSize: 41 | Max: 134 42 | 43 | # Offense count: 3 44 | # Configuration parameters: CountComments, CountAsOne. 45 | Metrics/ClassLength: 46 | Max: 2018 47 | 48 | # Offense count: 45 49 | # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. 50 | Metrics/MethodLength: 51 | Max: 141 52 | 53 | # Offense count: 4 54 | # Configuration parameters: CountKeywordArgs, MaxOptionalParameters. 55 | Metrics/ParameterLists: 56 | Max: 7 57 | 58 | # Offense count: 4 59 | # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, Regex, IgnoreExecutableScripts, AllowedAcronyms. 60 | # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS 61 | Naming/FileName: 62 | Exclude: 63 | - 'gemfiles/Sinatra_1.gemfile' 64 | - 'gemfiles/Sinatra_2.gemfile' 65 | - 'lib/sendgrid-ruby.rb' 66 | - 'test/sendgrid/test_sendgrid-ruby.rb' 67 | 68 | # Offense count: 1 69 | # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. 70 | # AllowedNames: at, by, db, id, in, io, ip, of, on, os, pp, to 71 | Naming/MethodParameterName: 72 | Exclude: 73 | - 'lib/sendgrid/helpers/mail/personalization.rb' 74 | 75 | # Offense count: 1 76 | # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. 77 | # NamePrefix: is_, has_, have_ 78 | # ForbiddenPrefixes: is_, has_, have_ 79 | # AllowedMethods: is_a? 80 | # MethodDefinitionMacros: define_method, define_singleton_method 81 | Naming/PredicateName: 82 | Exclude: 83 | - 'spec/**/*' 84 | - 'examples/helpers/eventwebhook/example.rb' 85 | 86 | # Offense count: 35 87 | # Configuration parameters: AllowedConstants. 88 | Style/Documentation: 89 | Enabled: false 90 | 91 | # Offense count: 3 92 | # Configuration parameters: MaxUnannotatedPlaceholdersAllowed, IgnoredMethods. 93 | # SupportedStyles: annotated, template, unannotated 94 | Style/FormatStringToken: 95 | EnforcedStyle: unannotated 96 | 97 | # Offense count: 97 98 | # Cop supports --auto-correct. 99 | # Configuration parameters: EnforcedStyle. 100 | # SupportedStyles: always, always_true, never 101 | Style/FrozenStringLiteralComment: 102 | Enabled: false 103 | 104 | # Offense count: 1 105 | # Cop supports --auto-correct. 106 | # Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. 107 | # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys 108 | Style/HashSyntax: 109 | Exclude: 110 | - 'Gemfile' 111 | 112 | # Offense count: 6 113 | Style/MixinUsage: 114 | Exclude: 115 | - 'examples/helpers/eventwebhook/example.rb' 116 | - 'examples/helpers/mail/example.rb' 117 | - 'examples/helpers/settings/example.rb' 118 | - 'examples/helpers/stats/example.rb' 119 | - 'test/sendgrid/helpers/mail/test_attachment.rb' 120 | - 'test/sendgrid/helpers/mail/test_mail.rb' 121 | 122 | # Offense count: 54 123 | # Cop supports --auto-correct. 124 | # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. 125 | # URISchemes: http, https 126 | Layout/LineLength: 127 | Max: 381 128 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at open-source@twilio.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid open-source libraries. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. 2 | 3 | **All third-party contributors acknowledge that any contributions they provide will be made under the same open-source license that the open-source project is provided under.** 4 | - [Improvements to the Codebase](#improvements-to-the-codebase) 5 | - [Development Environment](#development-environment) 6 | - [Install and Run Locally](#install-and-run-locally) 7 | - [Prerequisites](#prerequisites) 8 | - [Initial setup:](#initial-setup) 9 | - [Environment Variables](#environment-variables) 10 | - [Execute:](#execute) 11 | - [Understanding the Code Base](#understanding-the-code-base) 12 | - [Testing](#testing) 13 | - [Style Guidelines & Naming Conventions](#style-guidelines--naming-conventions) 14 | - [Creating a Pull Request](#creating-a-pull-request) 15 | - [Code Reviews](#code-reviews) 16 | 17 | There are a few ways to contribute, which we'll enumerate below: 18 | 19 | 20 | ## Improvements to the Codebase 21 | 22 | We welcome direct contributions to the sendgrid-ruby code base. Thank you! 23 | 24 | ### Development Environment ### 25 | 26 | #### Install and Run Locally #### 27 | 28 | ##### Prerequisites ##### 29 | 30 | - Ruby 2.1+ 31 | - [ruby_http_client](https://github.com/sendgrid/ruby-http-client) 32 | 33 | 34 | ##### Initial setup: ##### 35 | 36 | 1. Clone the project 37 | 38 | ```bash 39 | git clone https://github.com/sendgrid/sendgrid-ruby.git 40 | cd sendgrid-ruby 41 | ``` 42 | 43 | 1. Install bundler and bundle 44 | 45 | ```bash 46 | bundle install 47 | ``` 48 | 49 | ### Environment Variables 50 | 51 | First, get your free Twilio SendGrid account [here](https://sendgrid.com/free?source=sendgrid-ruby). 52 | 53 | Next, update your environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys). 54 | 55 | ```bash 56 | echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env 57 | echo "sendgrid.env" >> .gitignore 58 | source ./sendgrid.env 59 | ``` 60 | 61 | ##### Execute: ##### 62 | 63 | See the [examples folder](examples) to get started quickly. 64 | 65 | To run the examples using the local version of this library from the root directory of this repo, please replace: 66 | 67 | `require 'sendgrid-ruby'` 68 | 69 | with: 70 | 71 | `require_relative './lib/sendgrid-ruby.rb'` 72 | 73 | Then run using: 74 | 75 | ```bash 76 | ruby example.rb 77 | ``` 78 | 79 | 80 | ## Understanding the Code Base 81 | 82 | **/examples** 83 | 84 | Working examples that demonstrate usage. 85 | 86 | **/test** 87 | 88 | Tests for the mail send and Web API v3 endpoints. 89 | 90 | **/lib** 91 | 92 | The Web API v3 client is `sendgrid-ruby.rb` 93 | 94 | ## Testing 95 | 96 | All PRs require passing tests before the PR will be reviewed. All test files are in the [`tests`](test) directory. For the purposes of contributing to this repo, please update the [`test_sendgrid-ruby.rb`](test/sendgrid/test_sendgrid-ruby.rb) file with unit tests as you modify the code. 97 | 98 | The integration tests require a Twilio SendGrid mock API in order to execute. We've simplified setting this up using Docker to run the tests. You will just need [Docker Desktop](https://docs.docker.com/get-docker/) and `make`. 99 | 100 | Once these are available, simply execute the Docker test target to run all tests: `make test-docker`. This command can also be used to open an interactive shell into the container where this library is installed. To start a *bash* shell for example, use this command: `command=bash make test-docker`. 101 | 102 | 103 | ## Style Guidelines & Naming Conventions 104 | 105 | Generally, we follow the style guidelines as suggested by the official language. However, we ask that you conform to the styles that already exist in the library. If you wish to deviate, please explain your reasoning. 106 | 107 | - [Community Driven Style Guide](https://github.com/bbatsov/ruby-style-guide) 108 | 109 | Please run your code through: 110 | 111 | - [rubocop](https://github.com/bbatsov/rubocop). 112 | 113 | 114 | ## Creating a Pull Request 115 | 116 | 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, 117 | and configure the remotes: 118 | 119 | ```bash 120 | # Clone your fork of the repo into the current directory 121 | git clone https://github.com/sendgrid/sendgrid-ruby 122 | 123 | # Navigate to the newly cloned directory 124 | cd sendgrid-ruby 125 | 126 | # Assign the original repo to a remote called "upstream" 127 | git remote add upstream https://github.com/sendgrid/sendgrid-ruby 128 | ``` 129 | 130 | 2. If you cloned a while ago, get the latest changes from upstream: 131 | 132 | ```bash 133 | git checkout 134 | git pull upstream 135 | ``` 136 | 137 | 3. Create a new topic branch (off the main project development branch) to 138 | contain your feature, change, or fix: 139 | 140 | ```bash 141 | git checkout -b 142 | ``` 143 | 144 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 145 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 146 | or your code is unlikely to be merged into the main project. Use Git's 147 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 148 | feature to tidy up your commits before making them public. 149 | 150 | 4a. Create tests. 151 | 152 | 4b. Create or update the example code that demonstrates the functionality of this change to the code. 153 | 154 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 155 | 156 | ```bash 157 | git pull [--rebase] upstream main 158 | ``` 159 | 160 | 6. Push your topic branch up to your fork: 161 | 162 | ```bash 163 | git push origin 164 | ``` 165 | 166 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 167 | with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. 168 | 169 | 170 | ## Code Reviews 171 | 172 | If you can, please look at open PRs and review them. Give feedback and help us merge these PRs much faster! If you don't know how, Github has some [great information on how to review a Pull Request](https://help.github.com/articles/about-pull-request-reviews/). 173 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG version=ruby:latest 2 | FROM $version 3 | 4 | # Needed for jruby 5 | RUN apt-get update \ 6 | && apt-get install -y make git 7 | 8 | COPY prism/prism/nginx/cert.crt /usr/local/share/ca-certificates/cert.crt 9 | RUN update-ca-certificates 10 | 11 | WORKDIR /app 12 | COPY . . 13 | 14 | RUN make install 15 | -------------------------------------------------------------------------------- /FIRST_TIMERS.md: -------------------------------------------------------------------------------- 1 | # How To Contribute to Twilio SendGrid Repositories via GitHub 2 | Contributing to the Twilio SendGrid repositories is easy! All you need to do is find an open issue (see the bottom of this page for a list of repositories containing open issues), fix it and submit a pull request. Once you have submitted your pull request, the team can easily review it before it is merged into the repository. 3 | 4 | To make a pull request, follow these steps: 5 | 6 | 1. Log into GitHub. If you do not already have a GitHub account, you will have to create one in order to submit a change. Click the Sign up link in the upper right-hand corner to create an account. Enter your username, password, and email address. If you are an employee of Twilio SendGrid, please use your full name with your GitHub account and enter Twilio SendGrid as your company so we can easily identify you. 7 | 8 | 9 | 10 | 2. __[Fork](https://help.github.com/fork-a-repo/)__ the [sendgrid-ruby](https://github.com/sendgrid/sendgrid-ruby) repository: 11 | 12 | 13 | 14 | 3. __Clone__ your fork via the following commands: 15 | 16 | ```bash 17 | # Clone your fork of the repo into the current directory 18 | git clone https://github.com/your_username/sendgrid-ruby 19 | # Navigate to the newly cloned directory 20 | cd sendgrid-ruby 21 | # Assign the original repo to a remote called "upstream" 22 | git remote add upstream https://github.com/sendgrid/sendgrid-ruby 23 | ``` 24 | 25 | > Don't forget to replace *your_username* in the URL by your real GitHub username. 26 | 27 | 4. __Create a new topic branch__ (off the main project development branch) to contain your feature, change, or fix: 28 | 29 | ```bash 30 | git checkout -b 31 | ``` 32 | 33 | 5. __Commit your changes__ in logical chunks. 34 | 35 | Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your code is unlikely be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. Probably you will also have to create tests (if needed) or create or update the example code that demonstrates the functionality of this change to the code. 36 | 37 | 6. __Locally merge (or rebase)__ the upstream development branch into your topic branch: 38 | 39 | ```bash 40 | git pull [--rebase] upstream main 41 | ``` 42 | 43 | 7. __Push__ your topic branch up to your fork: 44 | 45 | ```bash 46 | git push origin 47 | ``` 48 | 49 | 8. __[Open a Pull Request](https://help.github.com/articles/creating-a-pull-request/#changing-the-branch-range-and-destination-repository/)__ with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. 50 | 51 | ## Important notice 52 | 53 | Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](CONTRIBUTING.md) file. 54 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem 'ruby_http_client' 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2023, Twilio SendGrid, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: install test test-integ test-docker 2 | 3 | install: 4 | gem install bundler:2.1.2; bundle install 5 | 6 | test: 7 | bundle exec rake 8 | 9 | test-integ: test 10 | 11 | version ?= ruby:latest 12 | test-docker: 13 | curl -s https://raw.githubusercontent.com/sendgrid/sendgrid-oai/HEAD/prism/prism.sh -o prism.sh 14 | version=$(version) bash ./prism.sh 15 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 16 | 17 | # Fixes # 18 | 19 | A short description of what this PR does. 20 | 21 | ### Checklist 22 | - [x] I acknowledge that all my contributions will be made under the project's license 23 | - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) 24 | - [ ] I have read the [Contribution Guidelines](https://github.com/sendgrid/sendgrid-ruby/blob/main/CONTRIBUTING.md) and my PR follows them 25 | - [ ] I have titled the PR appropriately 26 | - [ ] I have updated my branch with the main branch 27 | - [ ] I have added tests that prove my fix is effective or that my feature works 28 | - [ ] I have added the necessary documentation about the functionality in the appropriate .md file 29 | - [ ] I have added inline documentation to the code I modified 30 | 31 | If you have questions, please file a [support ticket](https://support.sendgrid.com), or create a GitHub Issue in this repository. 32 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'bundler/gem_tasks' 3 | require 'rspec/core/rake_task' 4 | 5 | Rake::TestTask.new do |t| 6 | t.libs << 'test' 7 | t.test_files = FileList['test/sendgrid/test*.rb', 'test/sendgrid/helpers/mail/test*.rb', 'test/sendgrid/helpers/permissions/test*.rb'] 8 | t.verbose = true 9 | end 10 | 11 | RSpec::Core::RakeTask.new(:spec) 12 | 13 | desc 'Run tests' 14 | task default: %i[spec test] 15 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | If you have an issue logging into your Twilio SendGrid account, please read this [document](https://sendgrid.com/docs/ui/account-and-settings/troubleshooting-login/). For any questions regarding login issues, please contact our [support team](https://support.sendgrid.com). 2 | 3 | If you have a non-library Twilio SendGrid issue, please contact our [support team](https://support.sendgrid.com). 4 | 5 | If you can't find a solution below, please open an [issue](https://github.com/sendgrid/sendgrid-ruby/issues). 6 | 7 | 8 | ## Table of Contents 9 | 10 | * [Migrating from v2 to v3](#migrating-from-v2-to-v3) 11 | * [Continue Using v2](#continue-using-v2) 12 | * [Testing v3 /mail/send Calls Directly](#testing-v3-mailsend-calls-directly) 13 | * [Error Messages](#error-messages) 14 | * [Versioning](#versioning) 15 | * [Environment Variables and Your Twilio SendGrid API Key](#environment-variables-and-your-twilio-sendgrid-api-key) 16 | * [Using the Package Manager](#using-the-package-manager) 17 | * [Rails Specifics](#rails-specifics) 18 | * [Ruby Versions](#ruby-versions) 19 | * [Viewing the Request Body](#viewing-the-request-body) 20 | * [Verifying Event Webhooks](#signed-webhooks) 21 | 22 | 23 | ## Migrating from v2 to v3 24 | 25 | Please review [our guide](https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/how_to_migrate_from_v2_to_v3_mail_send.html) on how to migrate from v2 to v3. 26 | 27 | 28 | ## Continue Using v2 29 | 30 | [Here](https://github.com/sendgrid/sendgrid-ruby/tree/0fbf579c0f7ed1dff87adc4957c4dc5a6b257068) is the last working version with v2 support. 31 | 32 | Using RubyGems: 33 | 34 | Add this line to your application's Gemfile: 35 | 36 | ```bash 37 | gem 'sendgrid-ruby', '1.1.6' 38 | ``` 39 | 40 | And then execute: 41 | 42 | ```bash 43 | bundle 44 | ``` 45 | 46 | Or install it yourself using: 47 | 48 | ```bash 49 | gem install sendgrid-ruby -v 1.1.6 50 | ``` 51 | 52 | Download: 53 | 54 | Click the "Clone or download" green button in [GitHub](https://github.com/sendgrid/sendgrid-ruby/tree/0fbf579c0f7ed1dff87adc4957c4dc5a6b257068) and choose download. 55 | 56 | 57 | ## Testing v3 /mail/send Calls Directly 58 | 59 | [Here](https://sendgrid.com/docs/for-developers/sending-email/curl-examples/) are some cURL examples for common use cases. 60 | 61 | 62 | ## Error Messages 63 | 64 | To read the error message returned by SendGrid's API: 65 | 66 | ```ruby 67 | begin 68 | response = sg.client.mail._("send").post(request_body: mail.to_json) 69 | rescue Exception => e 70 | puts e.message 71 | end 72 | ``` 73 | 74 | 75 | ## Versioning 76 | 77 | We follow the MAJOR.MINOR.PATCH versioning scheme as described by [SemVer.org](http://semver.org). Therefore, we recommend that you always pin (or vendor) the particular version you are working with your code and never auto-update to the latest version. Especially when there is a MAJOR point release since that is guaranteed to be a breaking change. Changes are documented in the [CHANGELOG](CHANGELOG.md) and [releases](https://github.com/sendgrid/sendgrid-ruby/releases) section. 78 | 79 | 80 | ## Environment Variables and Your Twilio SendGrid API Key 81 | 82 | All of our examples assume you are using [environment variables](https://github.com/sendgrid/sendgrid-ruby#setup-environment-variables) to hold your Twilio SendGrid API key. 83 | 84 | If you choose to add your Twilio SendGrid API key directly (not recommended): 85 | 86 | `sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])` 87 | 88 | becomes 89 | 90 | `sg = SendGrid::API.new(api_key: 'SENDGRID_API_KEY')` 91 | 92 | In the first case, SENDGRID_API_KEY is in reference to the name of the environment variable, while the second case references the actual Twilio SendGrid API Key. 93 | 94 | 95 | ## Using the Package Manager 96 | 97 | We upload this library to [RubyGems](https://rubygems.org/gems/sendgrid-ruby) whenever we make a release. This allows you to use [RubyGems](https://rubygems.org) for easy installation. 98 | 99 | In most cases we recommend you download the latest version of the library, but if you need a different version, please use: 100 | 101 | Add this line to your application's Gemfile: 102 | 103 | ```bash 104 | gem 'sendgrid-ruby', 'X.X.X' 105 | ``` 106 | 107 | And then execute: 108 | 109 | ```bash 110 | bundle 111 | ``` 112 | 113 | Or install it yourself using: 114 | 115 | ```bash 116 | gem install sendgrid-ruby -v X.X.X 117 | ``` 118 | 119 | 120 | ## Rails Specifics 121 | 122 | - Namespace collision between Rails own `Mail` class and sendgrid class `Mail`. To avoid that issues please use `SendGrid:: Mail` instead. 123 | 124 | - The possibility of a namespace collision between the sendgrid class `Email` and your own defined `Email` class. To avoid these issues, you can skip the `include SendGrid` line and use the `SendGrid::` prefix for Email. Please see this [SO answer](https://stackoverflow.com/questions/41508464/rails-model-name-conflict-with-included-gem?noredirect=1#comment70223099_41508464) for specifics. 125 | 126 | 127 | ## Ruby Versions 128 | 129 | This SDK [does not work with ruby version 2.6.0](https://github.com/sendgrid/sendgrid-ruby/issues/378) because of [this bug](https://bugs.ruby-lang.org/issues/15468). Please use any other [supported version](https://github.com/sendgrid/sendgrid-ruby#prerequisites). 130 | 131 | 132 | ## Viewing the Request Body 133 | 134 | When debugging or testing, it may be useful to examine the raw request header to compare against the [documented format](https://sendgrid.com/docs/API_Reference/api_v3.html). 135 | 136 | You can do this before `response = sg.client.mail._('send').post(request_body: mail.to_json)` like so: 137 | 138 | ```ruby 139 | puts mail.to_json 140 | ``` 141 | 142 | 143 | ## Signed Webhook Verification 144 | 145 | Twilio SendGrid's Event Webhook will notify a URL via HTTP POST with information about events that occur as your mail is processed. [This](https://docs.sendgrid.com/for-developers/tracking-events/getting-started-event-webhook-security-features) article covers all you need to know to secure the Event Webhook, allowing you to verify that incoming requests originate from Twilio SendGrid. The sendgrid-ruby library can help you verify these Signed Event Webhooks. 146 | 147 | You can find the usage example [here](examples/helpers/eventwebhook/example.rb) and the tests [here](spec/sendgrid/helpers/eventwebhook/eventwebhook_spec.rb). 148 | If you are still having trouble getting the validation to work, follow the following instructions: 149 | - Be sure to use the *raw* payload for validation 150 | - Be sure to include a trailing carriage return and newline in your payload 151 | - In case of multi-event webhooks, make sure you include the trailing newline and carriage return after *each* event 152 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | # Upgrading from 5.X to 6.X 2 | 3 | Note, this is only necessary if you are using inbound processing. 4 | 5 | * Add this gem to your Gemfile: `gem 'sinatra', '>= 1.4.7', '< 3'` -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require './lib/sendgrid/helpers/inbound/app' 2 | 3 | use Rack::Reloader, 0 4 | run Main 5 | -------------------------------------------------------------------------------- /examples/accesssettings/accesssettings.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve all recent access attempts # 7 | # GET /access_settings/activity # 8 | 9 | params = JSON.parse('{"limit": 1}') 10 | response = sg.client.access_settings.activity.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Add one or more IPs to the whitelist # 17 | # POST /access_settings/whitelist # 18 | 19 | data = JSON.parse('{ 20 | "ips": [ 21 | { 22 | "ip": "192.168.1.1" 23 | }, 24 | { 25 | "ip": "192.*.*.*" 26 | }, 27 | { 28 | "ip": "192.168.1.3/32" 29 | } 30 | ] 31 | }') 32 | response = sg.client.access_settings.whitelist.post(request_body: data) 33 | puts response.status_code 34 | puts response.body 35 | puts response.headers 36 | 37 | ################################################## 38 | # Retrieve a list of currently whitelisted IPs # 39 | # GET /access_settings/whitelist # 40 | 41 | response = sg.client.access_settings.whitelist.get 42 | puts response.status_code 43 | puts response.body 44 | puts response.headers 45 | 46 | ################################################## 47 | # Remove one or more IPs from the whitelist # 48 | # DELETE /access_settings/whitelist # 49 | 50 | data = JSON.parse('{ 51 | "ids": [ 52 | 1, 53 | 2, 54 | 3 55 | ] 56 | }') 57 | response = sg.client.access_settings.whitelist.delete(request_body: data) 58 | puts response.status_code 59 | puts response.body 60 | puts response.headers 61 | 62 | ################################################## 63 | # Retrieve a specific whitelisted IP # 64 | # GET /access_settings/whitelist/{rule_id} # 65 | 66 | rule_id = 'test_url_param' 67 | response = sg.client.access_settings.whitelist._(rule_id).get 68 | puts response.status_code 69 | puts response.body 70 | puts response.headers 71 | 72 | ################################################## 73 | # Remove a specific IP from the whitelist # 74 | # DELETE /access_settings/whitelist/{rule_id} # 75 | 76 | rule_id = 'test_url_param' 77 | response = sg.client.access_settings.whitelist._(rule_id).delete 78 | puts response.status_code 79 | puts response.body 80 | puts response.headers 81 | -------------------------------------------------------------------------------- /examples/alerts/alerts.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create a new Alert # 7 | # POST /alerts # 8 | 9 | data = JSON.parse('{ 10 | "email_to": "example@example.com", 11 | "frequency": "daily", 12 | "type": "stats_notification" 13 | }') 14 | response = sg.client.alerts.post(request_body: data) 15 | puts response.status_code 16 | puts response.body 17 | puts response.headers 18 | 19 | ################################################## 20 | # Retrieve all alerts # 21 | # GET /alerts # 22 | 23 | response = sg.client.alerts.get 24 | puts response.status_code 25 | puts response.body 26 | puts response.headers 27 | 28 | ################################################## 29 | # Update an alert # 30 | # PATCH /alerts/{alert_id} # 31 | 32 | data = JSON.parse('{ 33 | "email_to": "example@example.com" 34 | }') 35 | alert_id = 'test_url_param' 36 | response = sg.client.alerts._(alert_id).patch(request_body: data) 37 | puts response.status_code 38 | puts response.body 39 | puts response.headers 40 | 41 | ################################################## 42 | # Retrieve a specific alert # 43 | # GET /alerts/{alert_id} # 44 | 45 | alert_id = 'test_url_param' 46 | response = sg.client.alerts._(alert_id).get 47 | puts response.status_code 48 | puts response.body 49 | puts response.headers 50 | 51 | ################################################## 52 | # Delete an alert # 53 | # DELETE /alerts/{alert_id} # 54 | 55 | alert_id = 'test_url_param' 56 | response = sg.client.alerts._(alert_id).delete 57 | puts response.status_code 58 | puts response.body 59 | puts response.headers 60 | -------------------------------------------------------------------------------- /examples/apikeys/apikeys.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create API keys # 7 | # POST /api_keys # 8 | 9 | data = JSON.parse('{ 10 | "name": "My API Key", 11 | "sample": "data", 12 | "scopes": [ 13 | "mail.send", 14 | "alerts.create", 15 | "alerts.read" 16 | ] 17 | }') 18 | response = sg.client.api_keys.post(request_body: data) 19 | puts response.status_code 20 | puts response.body 21 | puts response.headers 22 | 23 | ################################################## 24 | # Retrieve all API Keys belonging to the authenticated user # 25 | # GET /api_keys # 26 | 27 | params = JSON.parse('{"limit": 1}') 28 | response = sg.client.api_keys.get(query_params: params) 29 | puts response.status_code 30 | puts response.body 31 | puts response.headers 32 | 33 | ################################################## 34 | # Update the name & scopes of an API Key # 35 | # PUT /api_keys/{api_key_id} # 36 | 37 | data = JSON.parse('{ 38 | "name": "A New Hope", 39 | "scopes": [ 40 | "user.profile.read", 41 | "user.profile.update" 42 | ] 43 | }') 44 | api_key_id = 'test_url_param' 45 | response = sg.client.api_keys._(api_key_id).put(request_body: data) 46 | puts response.status_code 47 | puts response.body 48 | puts response.headers 49 | 50 | ################################################## 51 | # Update API keys # 52 | # PATCH /api_keys/{api_key_id} # 53 | 54 | data = JSON.parse('{ 55 | "name": "A New Hope" 56 | }') 57 | api_key_id = 'test_url_param' 58 | response = sg.client.api_keys._(api_key_id).patch(request_body: data) 59 | puts response.status_code 60 | puts response.body 61 | puts response.headers 62 | 63 | ################################################## 64 | # Retrieve an existing API Key # 65 | # GET /api_keys/{api_key_id} # 66 | 67 | api_key_id = 'test_url_param' 68 | response = sg.client.api_keys._(api_key_id).get 69 | puts response.status_code 70 | puts response.body 71 | puts response.headers 72 | 73 | ################################################## 74 | # Delete API keys # 75 | # DELETE /api_keys/{api_key_id} # 76 | 77 | api_key_id = 'test_url_param' 78 | response = sg.client.api_keys._(api_key_id).delete 79 | puts response.status_code 80 | puts response.body 81 | puts response.headers 82 | -------------------------------------------------------------------------------- /examples/asm/asm.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create a new suppression group # 7 | # POST /asm/groups # 8 | 9 | data = JSON.parse('{ 10 | "description": "Suggestions for products our users might like.", 11 | "is_default": true, 12 | "name": "Product Suggestions" 13 | }') 14 | response = sg.client.asm.groups.post(request_body: data) 15 | puts response.status_code 16 | puts response.body 17 | puts response.headers 18 | 19 | ################################################## 20 | # Retrieve information about multiple suppression groups # 21 | # GET /asm/groups # 22 | 23 | params = JSON.parse('{"id": 1}') 24 | response = sg.client.asm.groups.get(query_params: params) 25 | puts response.status_code 26 | puts response.body 27 | puts response.headers 28 | 29 | ################################################## 30 | # Update a suppression group. # 31 | # PATCH /asm/groups/{group_id} # 32 | 33 | data = JSON.parse('{ 34 | "description": "Suggestions for items our users might like.", 35 | "id": 103, 36 | "name": "Item Suggestions" 37 | }') 38 | group_id = 'test_url_param' 39 | response = sg.client.asm.groups._(group_id).patch(request_body: data) 40 | puts response.status_code 41 | puts response.body 42 | puts response.headers 43 | 44 | ################################################## 45 | # Get information on a single suppression group. # 46 | # GET /asm/groups/{group_id} # 47 | 48 | group_id = 'test_url_param' 49 | response = sg.client.asm.groups._(group_id).get 50 | puts response.status_code 51 | puts response.body 52 | puts response.headers 53 | 54 | ################################################## 55 | # Delete a suppression group. # 56 | # DELETE /asm/groups/{group_id} # 57 | 58 | group_id = 'test_url_param' 59 | response = sg.client.asm.groups._(group_id).delete 60 | puts response.status_code 61 | puts response.body 62 | puts response.headers 63 | 64 | ################################################## 65 | # Add suppressions to a suppression group # 66 | # POST /asm/groups/{group_id}/suppressions # 67 | 68 | data = JSON.parse('{ 69 | "recipient_emails": [ 70 | "test1@example.com", 71 | "test2@example.com" 72 | ] 73 | }') 74 | group_id = 'test_url_param' 75 | response = sg.client.asm.groups._(group_id).suppressions.post(request_body: data) 76 | puts response.status_code 77 | puts response.body 78 | puts response.headers 79 | 80 | ################################################## 81 | # Retrieve all suppressions for a suppression group # 82 | # GET /asm/groups/{group_id}/suppressions # 83 | 84 | group_id = 'test_url_param' 85 | response = sg.client.asm.groups._(group_id).suppressions.get 86 | puts response.status_code 87 | puts response.body 88 | puts response.headers 89 | 90 | ################################################## 91 | # Search for suppressions within a group # 92 | # POST /asm/groups/{group_id}/suppressions/search # 93 | 94 | data = JSON.parse('{ 95 | "recipient_emails": [ 96 | "exists1@example.com", 97 | "exists2@example.com", 98 | "doesnotexists@example.com" 99 | ] 100 | }') 101 | group_id = 'test_url_param' 102 | response = sg.client.asm.groups._(group_id).suppressions.search.post(request_body: data) 103 | puts response.status_code 104 | puts response.body 105 | puts response.headers 106 | 107 | ################################################## 108 | # Delete a suppression from a suppression group # 109 | # DELETE /asm/groups/{group_id}/suppressions/{email} # 110 | 111 | group_id = 'test_url_param' 112 | email = 'test_url_param' 113 | response = sg.client.asm.groups._(group_id).suppressions._(email).delete 114 | puts response.status_code 115 | puts response.body 116 | puts response.headers 117 | 118 | ################################################## 119 | # Retrieve all suppressions # 120 | # GET /asm/suppressions # 121 | 122 | response = sg.client.asm.suppressions.get 123 | puts response.status_code 124 | puts response.body 125 | puts response.headers 126 | 127 | ################################################## 128 | # Add recipient addresses to the global suppression group. # 129 | # POST /asm/suppressions/global # 130 | 131 | data = JSON.parse('{ 132 | "recipient_emails": [ 133 | "test1@example.com", 134 | "test2@example.com" 135 | ] 136 | }') 137 | response = sg.client.asm.suppressions.global.post(request_body: data) 138 | puts response.status_code 139 | puts response.body 140 | puts response.headers 141 | 142 | ################################################## 143 | # Retrieve a Global Suppression # 144 | # GET /asm/suppressions/global/{email} # 145 | 146 | email = 'test_url_param' 147 | response = sg.client.asm.suppressions.global._(email).get 148 | puts response.status_code 149 | puts response.body 150 | puts response.headers 151 | 152 | ################################################## 153 | # Delete a Global Suppression # 154 | # DELETE /asm/suppressions/global/{email} # 155 | 156 | email = 'test_url_param' 157 | response = sg.client.asm.suppressions.global._(email).delete 158 | puts response.status_code 159 | puts response.body 160 | puts response.headers 161 | 162 | ################################################## 163 | # Retrieve all suppression groups for an email address # 164 | # GET /asm/suppressions/{email} # 165 | 166 | email = 'test_url_param' 167 | response = sg.client.asm.suppressions._(email).get 168 | puts response.status_code 169 | puts response.body 170 | puts response.headers 171 | -------------------------------------------------------------------------------- /examples/browsers/browsers.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve email statistics by browser. # 7 | # GET /browsers/stats # 8 | 9 | params = JSON.parse('{"end_date": "2016-04-01", "aggregated_by": "day", "browsers": "test_string", "limit": "test_string", "offset": "test_string", "start_date": "2016-01-01"}') 10 | response = sg.client.browsers.stats.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | -------------------------------------------------------------------------------- /examples/campaigns/campaigns.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create a Campaign # 7 | # POST /campaigns # 8 | 9 | data = JSON.parse('{ 10 | "categories": [ 11 | "spring line" 12 | ], 13 | "custom_unsubscribe_url": "", 14 | "html_content": "

Check out our spring line!

", 15 | "ip_pool": "marketing", 16 | "list_ids": [ 17 | 110, 18 | 124 19 | ], 20 | "plain_content": "Check out our spring line!", 21 | "segment_ids": [ 22 | 110 23 | ], 24 | "sender_id": 124451, 25 | "subject": "New Products for Spring!", 26 | "suppression_group_id": 42, 27 | "title": "March Newsletter" 28 | }') 29 | response = sg.client.campaigns.post(request_body: data) 30 | puts response.status_code 31 | puts response.body 32 | puts response.headers 33 | 34 | ################################################## 35 | # Retrieve all Campaigns # 36 | # GET /campaigns # 37 | 38 | params = JSON.parse('{"limit": 1, "offset": 1}') 39 | response = sg.client.campaigns.get(query_params: params) 40 | puts response.status_code 41 | puts response.body 42 | puts response.headers 43 | 44 | ################################################## 45 | # Update a Campaign # 46 | # PATCH /campaigns/{campaign_id} # 47 | 48 | data = JSON.parse('{ 49 | "categories": [ 50 | "summer line" 51 | ], 52 | "html_content": "

Check out our summer line!

", 53 | "plain_content": "Check out our summer line!", 54 | "subject": "New Products for Summer!", 55 | "title": "May Newsletter" 56 | }') 57 | campaign_id = 'test_url_param' 58 | response = sg.client.campaigns._(campaign_id).patch(request_body: data) 59 | puts response.status_code 60 | puts response.body 61 | puts response.headers 62 | 63 | ################################################## 64 | # Retrieve a single campaign # 65 | # GET /campaigns/{campaign_id} # 66 | 67 | campaign_id = 'test_url_param' 68 | response = sg.client.campaigns._(campaign_id).get 69 | puts response.status_code 70 | puts response.body 71 | puts response.headers 72 | 73 | ################################################## 74 | # Delete a Campaign # 75 | # DELETE /campaigns/{campaign_id} # 76 | 77 | campaign_id = 'test_url_param' 78 | response = sg.client.campaigns._(campaign_id).delete 79 | puts response.status_code 80 | puts response.body 81 | puts response.headers 82 | 83 | ################################################## 84 | # Update a Scheduled Campaign # 85 | # PATCH /campaigns/{campaign_id}/schedules # 86 | 87 | data = JSON.parse('{ 88 | "send_at": 1489451436 89 | }') 90 | campaign_id = 'test_url_param' 91 | response = sg.client.campaigns._(campaign_id).schedules.patch(request_body: data) 92 | puts response.status_code 93 | puts response.body 94 | puts response.headers 95 | 96 | ################################################## 97 | # Schedule a Campaign # 98 | # POST /campaigns/{campaign_id}/schedules # 99 | 100 | data = JSON.parse('{ 101 | "send_at": 1489771528 102 | }') 103 | campaign_id = 'test_url_param' 104 | response = sg.client.campaigns._(campaign_id).schedules.post(request_body: data) 105 | puts response.status_code 106 | puts response.body 107 | puts response.headers 108 | 109 | ################################################## 110 | # View Scheduled Time of a Campaign # 111 | # GET /campaigns/{campaign_id}/schedules # 112 | 113 | campaign_id = 'test_url_param' 114 | response = sg.client.campaigns._(campaign_id).schedules.get 115 | puts response.status_code 116 | puts response.body 117 | puts response.headers 118 | 119 | ################################################## 120 | # Unschedule a Scheduled Campaign # 121 | # DELETE /campaigns/{campaign_id}/schedules # 122 | 123 | campaign_id = 'test_url_param' 124 | response = sg.client.campaigns._(campaign_id).schedules.delete 125 | puts response.status_code 126 | puts response.body 127 | puts response.headers 128 | 129 | ################################################## 130 | # Send a Campaign # 131 | # POST /campaigns/{campaign_id}/schedules/now # 132 | 133 | campaign_id = 'test_url_param' 134 | response = sg.client.campaigns._(campaign_id).schedules.now.post 135 | puts response.status_code 136 | puts response.body 137 | puts response.headers 138 | 139 | ################################################## 140 | # Send a Test Campaign # 141 | # POST /campaigns/{campaign_id}/schedules/test # 142 | 143 | data = JSON.parse('{ 144 | "to": "your.email@example.com" 145 | }') 146 | campaign_id = 'test_url_param' 147 | response = sg.client.campaigns._(campaign_id).schedules.test.post(request_body: data) 148 | puts response.status_code 149 | puts response.body 150 | puts response.headers 151 | -------------------------------------------------------------------------------- /examples/categories/categories.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve all categories # 7 | # GET /categories # 8 | 9 | params = JSON.parse('{"category": "test_string", "limit": 1, "offset": 1}') 10 | response = sg.client.categories.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Retrieve Email Statistics for Categories # 17 | # GET /categories/stats # 18 | 19 | params = JSON.parse('{"end_date": "2016-04-01", "aggregated_by": "day", "limit": 1, "offset": 1, "start_date": "2016-01-01", "categories": "test_string"}') 20 | response = sg.client.categories.stats.get(query_params: params) 21 | puts response.status_code 22 | puts response.body 23 | puts response.headers 24 | 25 | ################################################## 26 | # Retrieve sums of email stats for each category [Needs: Stats object defined, has category ID?] # 27 | # GET /categories/stats/sums # 28 | 29 | params = JSON.parse('{"end_date": "2016-04-01", "aggregated_by": "day", "limit": 1, "sort_by_metric": "test_string", "offset": 1, "start_date": "2016-01-01", "sort_by_direction": "asc"}') 30 | response = sg.client.categories.stats.sums.get(query_params: params) 31 | puts response.status_code 32 | puts response.body 33 | puts response.headers 34 | -------------------------------------------------------------------------------- /examples/clients/clients.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve email statistics by client type. # 7 | # GET /clients/stats # 8 | 9 | params = JSON.parse('{"aggregated_by": "day", "start_date": "2016-01-01", "end_date": "2016-04-01"}') 10 | response = sg.client.clients.stats.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Retrieve stats by a specific client type. # 17 | # GET /clients/{client_type}/stats # 18 | 19 | params = JSON.parse('{"aggregated_by": "day", "start_date": "2016-01-01", "end_date": "2016-04-01"}') 20 | client_type = 'test_url_param' 21 | response = sg.client.clients._(client_type).stats.get(query_params: params) 22 | puts response.status_code 23 | puts response.body 24 | puts response.headers 25 | -------------------------------------------------------------------------------- /examples/dataresidency/setregion.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | # Example 1 4 | # Sending using "global" data residency 5 | 6 | from = SendGrid::Email.new(email: 'example@abc.com') 7 | to = SendGrid::Email.new(email: 'example@abc.com') 8 | subject = 'Sending with Twilio SendGrid is Fun' 9 | content = SendGrid::Content.new(type: 'text/plain', value: 'and easy to do anywhere, even with Ruby') 10 | mail = SendGrid::Mail.new(from, subject, to, content) 11 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 12 | sg.sendgrid_data_residency(region: "global") 13 | puts sg.host 14 | response = sg.client.mail._('send').post(request_body: mail.to_json) 15 | puts response.status_code 16 | puts response.body 17 | puts response.headers 18 | 19 | # Example 2 20 | # Sending using "eu" data residency 21 | 22 | from = SendGrid::Email.new(email: 'example@abc.com') 23 | to = SendGrid::Email.new(email: 'example@abc.com') 24 | subject = 'Sending with Twilio SendGrid is Fun' 25 | content = SendGrid::Content.new(type: 'text/plain', value: 'and easy to do anywhere, even with Ruby') 26 | mail = SendGrid::Mail.new(from, subject, to, content) 27 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY_EU']) 28 | sg.sendgrid_data_residency(region: 'eu') 29 | puts sg.host 30 | response = sg.client.mail._('send').post(request_body: mail.to_json) 31 | puts response.status_code 32 | puts response.body 33 | puts response.headers 34 | 35 | # Example 3 36 | # Sending using no data residency 37 | 38 | from = SendGrid::Email.new(email: 'example@abc.com') 39 | to = SendGrid::Email.new(email: 'example@abc.com') 40 | subject = 'Sending with Twilio SendGrid is Fun' 41 | content = SendGrid::Content.new(type: 'text/plain', value: 'and easy to do anywhere, even with Ruby') 42 | mail = SendGrid::Mail.new(from, subject, to, content) 43 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 44 | puts sg.host 45 | response = sg.client.mail._('send').post(request_body: mail.to_json) 46 | puts response.status_code 47 | puts response.body 48 | puts response.headers 49 | -------------------------------------------------------------------------------- /examples/devices/devices.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve email statistics by device type. # 7 | # GET /devices/stats # 8 | 9 | params = JSON.parse('{"aggregated_by": "day", "limit": 1, "start_date": "2016-01-01", "end_date": "2016-04-01", "offset": 1}') 10 | response = sg.client.devices.stats.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | -------------------------------------------------------------------------------- /examples/emailactivity/emailactivity.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Filter all messages # 7 | # GET /messages # 8 | 9 | require 'erb' 10 | 11 | filter_key = 'to_email' 12 | filter_operator = ERB::Util.url_encode('=') 13 | filter_value = 'testing@sendgrid.net' 14 | filter_value = ERB::Util.url_encode(format('"%s"', filter_value)) 15 | query_params = {} 16 | query_params['query'] = format("%s%s%s", filter_key, filter_operator, filter_value) 17 | query_params['limit'] = '1' 18 | 19 | params = query_params 20 | response = sg.client.messages.get(query_params: params) 21 | puts response.status_code 22 | puts response.body 23 | puts response.headers 24 | 25 | ################################################## 26 | # Filter messages by message ID # 27 | # GET /messages/{msg_id} # 28 | 29 | msg_id = "test_url_param" 30 | response = sg.client.messages._(msg_id).get 31 | puts response.status_code 32 | puts response.body 33 | puts response.headers 34 | 35 | ################################################## 36 | # Request a CSV # 37 | # POST /messages/download # 38 | 39 | response = sg.client.messages.download.post 40 | puts response.status_code 41 | puts response.body 42 | puts response.headers 43 | 44 | ################################################## 45 | # Download CSV # 46 | # GET /messages/download/{download_uuid} # 47 | 48 | download_uuid = "test_url_param" 49 | response = sg.client.messages.download._(download_uuid).get 50 | puts response.status_code 51 | puts response.body 52 | puts response.headers 53 | -------------------------------------------------------------------------------- /examples/geo/geo.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve email statistics by country and state/province. # 7 | # GET /geo/stats # 8 | 9 | params = JSON.parse('{"end_date": "2016-04-01", "country": "US", "aggregated_by": "day", "limit": 1, "offset": 1, "start_date": "2016-01-01"}') 10 | response = sg.client.geo.stats.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | -------------------------------------------------------------------------------- /examples/helpers/eventwebhook/example.rb: -------------------------------------------------------------------------------- 1 | require 'sengrid-ruby' 2 | include SendGrid 3 | 4 | def is_valid_signature(request) 5 | public_key = 'base64-encoded public key' 6 | 7 | event_webhook = SendGrid::EventWebhook.new 8 | ec_public_key = event_webhook.convert_public_key_to_ecdsa(public_key) 9 | 10 | event_webhook.verify_signature( 11 | ec_public_key, 12 | request.body.read, 13 | request.env[SendGrid::EventWebhookHeader::SIGNATURE], 14 | request.env[SendGrid::EventWebhookHeader::TIMESTAMP] 15 | ) 16 | end 17 | -------------------------------------------------------------------------------- /examples/helpers/settings/example.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | include SendGrid 3 | 4 | sg_client = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']).client 5 | settings = SendGrid::Settings.new(sendgrid_client: sg_client) 6 | 7 | # Fetch settings 8 | response = settings.bcc 9 | puts response.status_code 10 | puts response.body 11 | puts response.headers 12 | 13 | # Turn on bcc settings 14 | response = settings.update_bcc(enabled: true, email: 'email@example.com') 15 | puts response.status_code 16 | puts response.body 17 | puts response.headers 18 | 19 | # Turn off bcc settings 20 | response = settings.update_bcc(enabled: false) 21 | puts response.status_code 22 | puts response.body 23 | puts response.headers 24 | -------------------------------------------------------------------------------- /examples/helpers/stats/example.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | require 'date' 3 | 4 | include SendGrid 5 | 6 | sg_client = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']).client 7 | stats = SendGrid::EmailStats.new(sendgrid_client: sg_client) 8 | 9 | # Fetch stats by day, between 2 dates 10 | from = Date.new(2017, 10, 1) 11 | to = Date.new(2017, 10, 12) 12 | 13 | email_stats = stats.by_day(from, to) 14 | 15 | email_stats.metrics 16 | 17 | unless email_stats.error? 18 | email_stats.metrics.each do |metric| 19 | puts "Date - #{metric.date}" 20 | puts "Number of Requests - #{metric.requests}" 21 | puts "Bounces - #{metric.bounces}" 22 | puts "Opens - #{metric.opens}" 23 | puts "Clicks - #{metric.clicks}" 24 | end 25 | end 26 | 27 | # Fetch stats by week, between 2 dates for a category 28 | from = Date.new(2017, 10, 1) 29 | to = Date.new(2017, 10, 12) 30 | category = 'abcd' 31 | 32 | email_stats = stats.by_week(from, to, category) 33 | 34 | unless email_stats.error? 35 | email_stats.metrics.each do |metric| 36 | puts "Date - #{metric.date}" 37 | puts "Number of Requests - #{metric.requests}" 38 | puts "Bounces - #{metric.bounces}" 39 | puts "Opens - #{metric.opens}" 40 | puts "Clicks - #{metric.clicks}" 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /examples/ips/ips.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve all IP addresses # 7 | # GET /ips # 8 | 9 | params = JSON.parse('{"subuser": "test_string", "ip": "test_string", "limit": 1, "exclude_whitelabels": "true", "offset": 1}') 10 | response = sg.client.ips.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Retrieve all assigned IPs # 17 | # GET /ips/assigned # 18 | 19 | response = sg.client.ips.assigned.get 20 | puts response.status_code 21 | puts response.body 22 | puts response.headers 23 | 24 | ################################################## 25 | # Retrieve unassigned IPs # 26 | # GET /ips # 27 | 28 | params = {} 29 | response = sg.client.ips.get(query_params: params) 30 | all_ips = JSON.parse(response.body) 31 | unassigned_ips = all_ips.select { |ip| ip.subusers.empty? } 32 | puts response.status_code 33 | puts response.body 34 | puts unassigned_ips 35 | puts response.headers 36 | 37 | ################################################## 38 | # Create an IP pool. # 39 | # POST /ips/pools # 40 | 41 | data = JSON.parse('{ 42 | "name": "marketing" 43 | }') 44 | response = sg.client.ips.pools.post(request_body: data) 45 | puts response.status_code 46 | puts response.body 47 | puts response.headers 48 | 49 | ################################################## 50 | # Retrieve all IP pools. # 51 | # GET /ips/pools # 52 | 53 | response = sg.client.ips.pools.get 54 | puts response.status_code 55 | puts response.body 56 | puts response.headers 57 | 58 | ################################################## 59 | # Update an IP pools name. # 60 | # PUT /ips/pools/{pool_name} # 61 | 62 | data = JSON.parse('{ 63 | "name": "new_pool_name" 64 | }') 65 | pool_name = 'test_url_param' 66 | response = sg.client.ips.pools._(pool_name).put(request_body: data) 67 | puts response.status_code 68 | puts response.body 69 | puts response.headers 70 | 71 | ################################################## 72 | # Retrieve all IPs in a specified pool. # 73 | # GET /ips/pools/{pool_name} # 74 | 75 | pool_name = 'test_url_param' 76 | response = sg.client.ips.pools._(pool_name).get 77 | puts response.status_code 78 | puts response.body 79 | puts response.headers 80 | 81 | ################################################## 82 | # Delete an IP pool. # 83 | # DELETE /ips/pools/{pool_name} # 84 | 85 | pool_name = 'test_url_param' 86 | response = sg.client.ips.pools._(pool_name).delete 87 | puts response.status_code 88 | puts response.body 89 | puts response.headers 90 | 91 | ################################################## 92 | # Add an IP address to a pool # 93 | # POST /ips/pools/{pool_name}/ips # 94 | 95 | data = JSON.parse('{ 96 | "ip": "0.0.0.0" 97 | }') 98 | pool_name = 'test_url_param' 99 | response = sg.client.ips.pools._(pool_name).ips.post(request_body: data) 100 | puts response.status_code 101 | puts response.body 102 | puts response.headers 103 | 104 | ################################################## 105 | # Remove an IP address from a pool. # 106 | # DELETE /ips/pools/{pool_name}/ips/{ip} # 107 | 108 | pool_name = 'test_url_param' 109 | ip = 'test_url_param' 110 | response = sg.client.ips.pools._(pool_name).ips._(ip).delete 111 | puts response.status_code 112 | puts response.body 113 | puts response.headers 114 | 115 | ################################################## 116 | # Add an IP to warmup # 117 | # POST /ips/warmup # 118 | 119 | data = JSON.parse('{ 120 | "ip": "0.0.0.0" 121 | }') 122 | response = sg.client.ips.warmup.post(request_body: data) 123 | puts response.status_code 124 | puts response.body 125 | puts response.headers 126 | 127 | ################################################## 128 | # Retrieve all IPs currently in warmup # 129 | # GET /ips/warmup # 130 | 131 | response = sg.client.ips.warmup.get 132 | puts response.status_code 133 | puts response.body 134 | puts response.headers 135 | 136 | ################################################## 137 | # Retrieve warmup status for a specific IP address # 138 | # GET /ips/warmup/{ip_address} # 139 | 140 | ip_address = 'test_url_param' 141 | response = sg.client.ips.warmup._(ip_address).get 142 | puts response.status_code 143 | puts response.body 144 | puts response.headers 145 | 146 | ################################################## 147 | # Remove an IP from warmup # 148 | # DELETE /ips/warmup/{ip_address} # 149 | 150 | ip_address = 'test_url_param' 151 | response = sg.client.ips.warmup._(ip_address).delete 152 | puts response.status_code 153 | puts response.body 154 | puts response.headers 155 | 156 | ################################################## 157 | # Retrieve all IP pools an IP address belongs to # 158 | # GET /ips/{ip_address} # 159 | 160 | ip_address = 'test_url_param' 161 | response = sg.client.ips._(ip_address).get 162 | puts response.status_code 163 | puts response.body 164 | puts response.headers 165 | -------------------------------------------------------------------------------- /examples/mail/mail.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create a batch ID # 7 | # POST /mail/batch # 8 | 9 | response = sg.client.mail.batch.post 10 | puts response.status_code 11 | puts response.body 12 | puts response.headers 13 | 14 | ################################################## 15 | # Validate batch ID # 16 | # GET /mail/batch/{batch_id} # 17 | 18 | batch_id = 'test_url_param' 19 | response = sg.client.mail.batch._(batch_id).get 20 | puts response.status_code 21 | puts response.body 22 | puts response.headers 23 | 24 | ################################################## 25 | # v3 Mail Send # 26 | # POST /mail/send # 27 | # This endpoint has a helper, check it out [here](https://github.com/sendgrid/sendgrid-ruby/blob/HEAD/lib/sendgrid/helpers/mail/README.md). 28 | 29 | data = JSON.parse('{ 30 | "asm": { 31 | "group_id": 1, 32 | "groups_to_display": [ 33 | 1, 34 | 2, 35 | 3 36 | ] 37 | }, 38 | "attachments": [ 39 | { 40 | "content": "[BASE64 encoded content block here]", 41 | "content_id": "ii_139db99fdb5c3704", 42 | "disposition": "inline", 43 | "filename": "file1.jpg", 44 | "name": "file1", 45 | "type": "jpg" 46 | } 47 | ], 48 | "batch_id": "[YOUR BATCH ID GOES HERE]", 49 | "categories": [ 50 | "category1", 51 | "category2" 52 | ], 53 | "content": [ 54 | { 55 | "type": "text/html", 56 | "value": "

Hello, world!

" 57 | } 58 | ], 59 | "custom_args": { 60 | "New Argument 1": "New Value 1", 61 | "activationAttempt": "1", 62 | "customerAccountNumber": "[CUSTOMER ACCOUNT NUMBER GOES HERE]" 63 | }, 64 | "from": { 65 | "email": "sam.smith@example.com", 66 | "name": "Sam Smith" 67 | }, 68 | "headers": {}, 69 | "ip_pool_name": "[YOUR POOL NAME GOES HERE]", 70 | "mail_settings": { 71 | "bcc": { 72 | "email": "ben.doe@example.com", 73 | "enable": true 74 | }, 75 | "bypass_list_management": { 76 | "enable": true 77 | }, 78 | "footer": { 79 | "enable": true, 80 | "html": "

Thanks
The Twilio SendGrid Team

", 81 | "text": "Thanks,/n The Twilio SendGrid Team" 82 | }, 83 | "sandbox_mode": { 84 | "enable": false 85 | }, 86 | "spam_check": { 87 | "enable": true, 88 | "post_to_url": "http://example.com/compliance", 89 | "threshold": 3 90 | } 91 | }, 92 | "personalizations": [ 93 | { 94 | "bcc": [ 95 | { 96 | "email": "sam.doe@example.com", 97 | "name": "Sam Doe" 98 | } 99 | ], 100 | "cc": [ 101 | { 102 | "email": "jane.doe@example.com", 103 | "name": "Jane Doe" 104 | } 105 | ], 106 | "custom_args": { 107 | "New Argument 1": "New Value 1", 108 | "activationAttempt": "1", 109 | "customerAccountNumber": "[CUSTOMER ACCOUNT NUMBER GOES HERE]" 110 | }, 111 | "headers": { 112 | "X-Accept-Language": "en", 113 | "X-Mailer": "MyApp" 114 | }, 115 | "send_at": 1409348513, 116 | "subject": "Hello, World!", 117 | "substitutions": { 118 | "id": "substitutions", 119 | "type": "object" 120 | }, 121 | "to": [ 122 | { 123 | "email": "john.doe@example.com", 124 | "name": "John Doe" 125 | } 126 | ] 127 | } 128 | ], 129 | "reply_to": { 130 | "email": "sam.smith@example.com", 131 | "name": "Sam Smith" 132 | }, 133 | "sections": { 134 | "section": { 135 | ":sectionName1": "section 1 text", 136 | ":sectionName2": "section 2 text" 137 | } 138 | }, 139 | "send_at": 1409348513, 140 | "subject": "Hello, World!", 141 | "template_id": "[YOUR TEMPLATE ID GOES HERE]", 142 | "tracking_settings": { 143 | "click_tracking": { 144 | "enable": true, 145 | "enable_text": true 146 | }, 147 | "ganalytics": { 148 | "enable": true, 149 | "utm_campaign": "[NAME OF YOUR REFERRER SOURCE]", 150 | "utm_content": "[USE THIS SPACE TO DIFFERENTIATE YOUR EMAIL FROM ADS]", 151 | "utm_medium": "[NAME OF YOUR MARKETING MEDIUM e.g. email]", 152 | "utm_name": "[NAME OF YOUR CAMPAIGN]", 153 | "utm_term": "[IDENTIFY PAID KEYWORDS HERE]" 154 | }, 155 | "open_tracking": { 156 | "enable": true, 157 | "substitution_tag": "%opentrack" 158 | }, 159 | "subscription_tracking": { 160 | "enable": true, 161 | "html": "If you would like to unsubscribe and stop receiving these emails <% clickhere %>.", 162 | "substitution_tag": "<%click here%>", 163 | "text": "If you would like to unsubscribe and stop receiveing these emails <% click here %>." 164 | } 165 | } 166 | }') 167 | response = sg.client.mail._('send').post(request_body: data) 168 | puts response.status_code 169 | puts response.body 170 | puts response.headers 171 | -------------------------------------------------------------------------------- /examples/mailboxproviders/mailboxproviders.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve email statistics by mailbox provider. # 7 | # GET /mailbox_providers/stats # 8 | 9 | params = JSON.parse('{"end_date": "2016-04-01", "mailbox_providers": "test_string", "aggregated_by": "day", "limit": 1, "offset": 1, "start_date": "2016-01-01"}') 10 | response = sg.client.mailbox_providers.stats.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | -------------------------------------------------------------------------------- /examples/mailsettings/mailsettings.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve all mail settings # 7 | # GET /mail_settings # 8 | 9 | params = JSON.parse('{"limit": 1, "offset": 1}') 10 | response = sg.client.mail_settings.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Update address whitelist mail settings # 17 | # PATCH /mail_settings/address_whitelist # 18 | 19 | data = JSON.parse('{ 20 | "enabled": true, 21 | "list": [ 22 | "email1@example.com", 23 | "example.com" 24 | ] 25 | }') 26 | response = sg.client.mail_settings.address_whitelist.patch(request_body: data) 27 | puts response.status_code 28 | puts response.body 29 | puts response.headers 30 | 31 | ################################################## 32 | # Retrieve address whitelist mail settings # 33 | # GET /mail_settings/address_whitelist # 34 | 35 | response = sg.client.mail_settings.address_whitelist.get 36 | puts response.status_code 37 | puts response.body 38 | puts response.headers 39 | 40 | ################################################## 41 | # Update BCC mail settings # 42 | # PATCH /mail_settings/bcc # 43 | 44 | data = JSON.parse('{ 45 | "email": "email@example.com", 46 | "enabled": false 47 | }') 48 | response = sg.client.mail_settings.bcc.patch(request_body: data) 49 | puts response.status_code 50 | puts response.body 51 | puts response.headers 52 | 53 | ################################################## 54 | # Retrieve all BCC mail settings # 55 | # GET /mail_settings/bcc # 56 | 57 | response = sg.client.mail_settings.bcc.get 58 | puts response.status_code 59 | puts response.body 60 | puts response.headers 61 | 62 | ################################################## 63 | # Update bounce purge mail settings # 64 | # PATCH /mail_settings/bounce_purge # 65 | 66 | data = JSON.parse('{ 67 | "enabled": true, 68 | "hard_bounces": 5, 69 | "soft_bounces": 5 70 | }') 71 | response = sg.client.mail_settings.bounce_purge.patch(request_body: data) 72 | puts response.status_code 73 | puts response.body 74 | puts response.headers 75 | 76 | ################################################## 77 | # Retrieve bounce purge mail settings # 78 | # GET /mail_settings/bounce_purge # 79 | 80 | response = sg.client.mail_settings.bounce_purge.get 81 | puts response.status_code 82 | puts response.body 83 | puts response.headers 84 | 85 | ################################################## 86 | # Update footer mail settings # 87 | # PATCH /mail_settings/footer # 88 | 89 | data = JSON.parse('{ 90 | "enabled": true, 91 | "html_content": "...", 92 | "plain_content": "..." 93 | }') 94 | response = sg.client.mail_settings.footer.patch(request_body: data) 95 | puts response.status_code 96 | puts response.body 97 | puts response.headers 98 | 99 | ################################################## 100 | # Retrieve footer mail settings # 101 | # GET /mail_settings/footer # 102 | 103 | response = sg.client.mail_settings.footer.get 104 | puts response.status_code 105 | puts response.body 106 | puts response.headers 107 | 108 | ################################################## 109 | # Update forward bounce mail settings # 110 | # PATCH /mail_settings/forward_bounce # 111 | 112 | data = JSON.parse('{ 113 | "email": "example@example.com", 114 | "enabled": true 115 | }') 116 | response = sg.client.mail_settings.forward_bounce.patch(request_body: data) 117 | puts response.status_code 118 | puts response.body 119 | puts response.headers 120 | 121 | ################################################## 122 | # Retrieve forward bounce mail settings # 123 | # GET /mail_settings/forward_bounce # 124 | 125 | response = sg.client.mail_settings.forward_bounce.get 126 | puts response.status_code 127 | puts response.body 128 | puts response.headers 129 | 130 | ################################################## 131 | # Update forward spam mail settings # 132 | # PATCH /mail_settings/forward_spam # 133 | 134 | data = JSON.parse('{ 135 | "email": "", 136 | "enabled": false 137 | }') 138 | response = sg.client.mail_settings.forward_spam.patch(request_body: data) 139 | puts response.status_code 140 | puts response.body 141 | puts response.headers 142 | 143 | ################################################## 144 | # Retrieve forward spam mail settings # 145 | # GET /mail_settings/forward_spam # 146 | 147 | response = sg.client.mail_settings.forward_spam.get 148 | puts response.status_code 149 | puts response.body 150 | puts response.headers 151 | 152 | ################################################## 153 | # Update plain content mail settings # 154 | # PATCH /mail_settings/plain_content # 155 | 156 | data = JSON.parse('{ 157 | "enabled": false 158 | }') 159 | response = sg.client.mail_settings.plain_content.patch(request_body: data) 160 | puts response.status_code 161 | puts response.body 162 | puts response.headers 163 | 164 | ################################################## 165 | # Retrieve plain content mail settings # 166 | # GET /mail_settings/plain_content # 167 | 168 | response = sg.client.mail_settings.plain_content.get 169 | puts response.status_code 170 | puts response.body 171 | puts response.headers 172 | 173 | ################################################## 174 | # Update spam check mail settings # 175 | # PATCH /mail_settings/spam_check # 176 | 177 | data = JSON.parse('{ 178 | "enabled": true, 179 | "max_score": 5, 180 | "url": "url" 181 | }') 182 | response = sg.client.mail_settings.spam_check.patch(request_body: data) 183 | puts response.status_code 184 | puts response.body 185 | puts response.headers 186 | 187 | ################################################## 188 | # Retrieve spam check mail settings # 189 | # GET /mail_settings/spam_check # 190 | 191 | response = sg.client.mail_settings.spam_check.get 192 | puts response.status_code 193 | puts response.body 194 | puts response.headers 195 | 196 | ################################################## 197 | # Update template mail settings # 198 | # PATCH /mail_settings/template # 199 | 200 | data = JSON.parse('{ 201 | "enabled": true, 202 | "html_content": "<% body %>" 203 | }') 204 | response = sg.client.mail_settings.template.patch(request_body: data) 205 | puts response.status_code 206 | puts response.body 207 | puts response.headers 208 | 209 | ################################################## 210 | # Retrieve legacy template mail settings # 211 | # GET /mail_settings/template # 212 | 213 | response = sg.client.mail_settings.template.get 214 | puts response.status_code 215 | puts response.body 216 | puts response.headers 217 | -------------------------------------------------------------------------------- /examples/partnersettings/partnersettings.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Returns a list of all partner settings. # 7 | # GET /partner_settings # 8 | 9 | params = JSON.parse('{"limit": 1, "offset": 1}') 10 | response = sg.client.partner_settings.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Updates New Relic partner settings. # 17 | # PATCH /partner_settings/new_relic # 18 | 19 | data = JSON.parse('{ 20 | "enable_subuser_statistics": true, 21 | "enabled": true, 22 | "license_key": "" 23 | }') 24 | response = sg.client.partner_settings.new_relic.patch(request_body: data) 25 | puts response.status_code 26 | puts response.body 27 | puts response.headers 28 | 29 | ################################################## 30 | # Returns all New Relic partner settings. # 31 | # GET /partner_settings/new_relic # 32 | 33 | response = sg.client.partner_settings.new_relic.get 34 | puts response.status_code 35 | puts response.body 36 | puts response.headers 37 | -------------------------------------------------------------------------------- /examples/scopes/scopes.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../lib/sendgrid-ruby' 2 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 3 | 4 | ################################################## 5 | # Retrieve a list of scopes for which this user has access. # 6 | # GET /scopes # 7 | 8 | response = sg.client.scopes.get 9 | puts response.status_code 10 | puts response.body 11 | puts response.headers 12 | 13 | ################################################## 14 | # Update the name & scopes of an API Key # 15 | # PUT /api_keys/{api_key_id} # 16 | 17 | scopes = [ 18 | "user.profile.read", 19 | "user.profile.update" 20 | ] 21 | 22 | data = { 23 | "name": "A New Hope", 24 | "scopes": scopes 25 | } 26 | api_key_id = "test_url_param" 27 | response = sg.client.api_keys._(api_key_id).put(request_body: data) 28 | puts response.status_code 29 | puts response.body 30 | puts response.headers 31 | 32 | # The above method shows how to update the scopes 33 | # To get various scopes that each of the endpoint has, use the following 34 | 35 | # To get all admin permissions 36 | scopes = SendGrid::Scope.admin_permissions 37 | 38 | # To get all read only permissions 39 | scopes = SendGrid::Scope.read_only_permissions 40 | 41 | # There are two methods for each endpoints, namely 42 | # {endpoint}_read_only_permissions and {endpoint}_full_access_permissions 43 | 44 | # These are the endpoints : 45 | # alerts, api_keys, asm_groups, billing, categories, credentials, stats, ips, mail_settings, mail, 46 | # marketing_campaigns, partner_settings, scheduled_sends, subusers, suppression, teammates, 47 | # templates, tracking_settings, user_settings, webhooks, whitelabel, access_settings 48 | 49 | # read only permissions for alerts 50 | scopes = SendGrid::Scope.alerts_read_only_permissions 51 | 52 | # full access permissions for alerts 53 | scopes = SendGrid::Scope.alerts_full_access_permissions 54 | 55 | # read only permissions for billing 56 | scopes = SendGrid::Scope.billing_read_only_permissions 57 | 58 | # full access permissions for billing 59 | scopes = SendGrid::Scope.billing_full_access_permissions 60 | -------------------------------------------------------------------------------- /examples/senders/senders.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create a Sender Identity # 7 | # POST /senders # 8 | 9 | data = JSON.parse('{ 10 | "address": "123 Elm St.", 11 | "address_2": "Apt. 456", 12 | "city": "Denver", 13 | "country": "United States", 14 | "from": { 15 | "email": "from@example.com", 16 | "name": "Example INC" 17 | }, 18 | "nickname": "My Sender ID", 19 | "reply_to": { 20 | "email": "replyto@example.com", 21 | "name": "Example INC" 22 | }, 23 | "state": "Colorado", 24 | "zip": "80202" 25 | }') 26 | response = sg.client.senders.post(request_body: data) 27 | puts response.status_code 28 | puts response.body 29 | puts response.headers 30 | 31 | ################################################## 32 | # Get all Sender Identities # 33 | # GET /senders # 34 | 35 | response = sg.client.senders.get 36 | puts response.status_code 37 | puts response.body 38 | puts response.headers 39 | 40 | ################################################## 41 | # Update a Sender Identity # 42 | # PATCH /senders/{sender_id} # 43 | 44 | data = JSON.parse('{ 45 | "address": "123 Elm St.", 46 | "address_2": "Apt. 456", 47 | "city": "Denver", 48 | "country": "United States", 49 | "from": { 50 | "email": "from@example.com", 51 | "name": "Example INC" 52 | }, 53 | "nickname": "My Sender ID", 54 | "reply_to": { 55 | "email": "replyto@example.com", 56 | "name": "Example INC" 57 | }, 58 | "state": "Colorado", 59 | "zip": "80202" 60 | }') 61 | sender_id = 'test_url_param' 62 | response = sg.client.senders._(sender_id).patch(request_body: data) 63 | puts response.status_code 64 | puts response.body 65 | puts response.headers 66 | 67 | ################################################## 68 | # View a Sender Identity # 69 | # GET /senders/{sender_id} # 70 | 71 | sender_id = 'test_url_param' 72 | response = sg.client.senders._(sender_id).get 73 | puts response.status_code 74 | puts response.body 75 | puts response.headers 76 | 77 | ################################################## 78 | # Delete a Sender Identity # 79 | # DELETE /senders/{sender_id} # 80 | 81 | sender_id = 'test_url_param' 82 | response = sg.client.senders._(sender_id).delete 83 | puts response.status_code 84 | puts response.body 85 | puts response.headers 86 | 87 | ################################################## 88 | # Resend Sender Identity Verification # 89 | # POST /senders/{sender_id}/resend_verification # 90 | 91 | sender_id = 'test_url_param' 92 | response = sg.client.senders._(sender_id).resend_verification.post 93 | puts response.status_code 94 | puts response.body 95 | puts response.headers 96 | -------------------------------------------------------------------------------- /examples/stats/stats.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve global email statistics # 7 | # GET /stats # 8 | 9 | params = JSON.parse('{"aggregated_by": "day", "limit": 1, "start_date": "2016-01-01", "end_date": "2016-04-01", "offset": 1}') 10 | response = sg.client.stats.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | -------------------------------------------------------------------------------- /examples/subusers/subusers.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create Subuser # 7 | # POST /subusers # 8 | 9 | data = JSON.parse('{ 10 | "email": "John@example.com", 11 | "ips": [ 12 | "1.1.1.1", 13 | "2.2.2.2" 14 | ], 15 | "password": "johns_password", 16 | "username": "John@example.com" 17 | }') 18 | response = sg.client.subusers.post(request_body: data) 19 | puts response.status_code 20 | puts response.body 21 | puts response.headers 22 | 23 | ################################################## 24 | # List all Subusers # 25 | # GET /subusers # 26 | 27 | params = JSON.parse('{"username": "test_string", "limit": 1, "offset": 1}') 28 | response = sg.client.subusers.get(query_params: params) 29 | puts response.status_code 30 | puts response.body 31 | puts response.headers 32 | 33 | ################################################## 34 | # Retrieve Subuser Reputations # 35 | # GET /subusers/reputations # 36 | 37 | params = JSON.parse('{"usernames": "test_string"}') 38 | response = sg.client.subusers.reputations.get(query_params: params) 39 | puts response.status_code 40 | puts response.body 41 | puts response.headers 42 | 43 | ################################################## 44 | # Retrieve email statistics for your subusers. # 45 | # GET /subusers/stats # 46 | 47 | params = JSON.parse('{"end_date": "2016-04-01", "aggregated_by": "day", "limit": 1, "offset": 1, "start_date": "2016-01-01", "subusers": "test_string"}') 48 | response = sg.client.subusers.stats.get(query_params: params) 49 | puts response.status_code 50 | puts response.body 51 | puts response.headers 52 | 53 | ################################################## 54 | # Retrieve monthly stats for all subusers # 55 | # GET /subusers/stats/monthly # 56 | 57 | params = JSON.parse('{"subuser": "test_string", "limit": 1, "sort_by_metric": "test_string", "offset": 1, "date": "test_string", "sort_by_direction": "asc"}') 58 | response = sg.client.subusers.stats.monthly.get(query_params: params) 59 | puts response.status_code 60 | puts response.body 61 | puts response.headers 62 | 63 | ################################################## 64 | # Retrieve the totals for each email statistic metric for all subusers. # 65 | # GET /subusers/stats/sums # 66 | 67 | params = JSON.parse('{"end_date": "2016-04-01", "aggregated_by": "day", "limit": 1, "sort_by_metric": "test_string", "offset": 1, "start_date": "2016-01-01", "sort_by_direction": "asc"}') 68 | response = sg.client.subusers.stats.sums.get(query_params: params) 69 | puts response.status_code 70 | puts response.body 71 | puts response.headers 72 | 73 | ################################################## 74 | # Enable/disable a subuser # 75 | # PATCH /subusers/{subuser_name} # 76 | 77 | data = JSON.parse('{ 78 | "disabled": false 79 | }') 80 | subuser_name = 'test_url_param' 81 | response = sg.client.subusers._(subuser_name).patch(request_body: data) 82 | puts response.status_code 83 | puts response.body 84 | puts response.headers 85 | 86 | ################################################## 87 | # Delete a subuser # 88 | # DELETE /subusers/{subuser_name} # 89 | 90 | subuser_name = 'test_url_param' 91 | response = sg.client.subusers._(subuser_name).delete 92 | puts response.status_code 93 | puts response.body 94 | puts response.headers 95 | 96 | ################################################## 97 | # Update IPs assigned to a subuser # 98 | # PUT /subusers/{subuser_name}/ips # 99 | 100 | data = JSON.parse('[ 101 | "127.0.0.1" 102 | ]') 103 | subuser_name = 'test_url_param' 104 | response = sg.client.subusers._(subuser_name).ips.put(request_body: data) 105 | puts response.status_code 106 | puts response.body 107 | puts response.headers 108 | 109 | ################################################## 110 | # Update Monitor Settings for a subuser # 111 | # PUT /subusers/{subuser_name}/monitor # 112 | 113 | data = JSON.parse('{ 114 | "email": "example@example.com", 115 | "frequency": 500 116 | }') 117 | subuser_name = 'test_url_param' 118 | response = sg.client.subusers._(subuser_name).monitor.put(request_body: data) 119 | puts response.status_code 120 | puts response.body 121 | puts response.headers 122 | 123 | ################################################## 124 | # Create monitor settings # 125 | # POST /subusers/{subuser_name}/monitor # 126 | 127 | data = JSON.parse('{ 128 | "email": "example@example.com", 129 | "frequency": 50000 130 | }') 131 | subuser_name = 'test_url_param' 132 | response = sg.client.subusers._(subuser_name).monitor.post(request_body: data) 133 | puts response.status_code 134 | puts response.body 135 | puts response.headers 136 | 137 | ################################################## 138 | # Retrieve monitor settings for a subuser # 139 | # GET /subusers/{subuser_name}/monitor # 140 | 141 | subuser_name = 'test_url_param' 142 | response = sg.client.subusers._(subuser_name).monitor.get 143 | puts response.status_code 144 | puts response.body 145 | puts response.headers 146 | 147 | ################################################## 148 | # Delete monitor settings # 149 | # DELETE /subusers/{subuser_name}/monitor # 150 | 151 | subuser_name = 'test_url_param' 152 | response = sg.client.subusers._(subuser_name).monitor.delete 153 | puts response.status_code 154 | puts response.body 155 | puts response.headers 156 | 157 | ################################################## 158 | # Retrieve the monthly email statistics for a single subuser # 159 | # GET /subusers/{subuser_name}/stats/monthly # 160 | 161 | params = JSON.parse('{"date": "test_string", "sort_by_direction": "asc", "limit": 1, "sort_by_metric": "test_string", "offset": 1}') 162 | subuser_name = 'test_url_param' 163 | response = sg.client.subusers._(subuser_name).stats.monthly.get(query_params: params) 164 | puts response.status_code 165 | puts response.body 166 | puts response.headers 167 | -------------------------------------------------------------------------------- /examples/suppression/suppression.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve all blocks # 7 | # GET /suppression/blocks # 8 | 9 | params = JSON.parse('{"start_time": 1, "limit": 1, "end_time": 1, "offset": 1}') 10 | response = sg.client.suppression.blocks.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Delete blocks # 17 | # DELETE /suppression/blocks # 18 | 19 | data = JSON.parse('{ 20 | "delete_all": false, 21 | "emails": [ 22 | "example1@example.com", 23 | "example2@example.com" 24 | ] 25 | }') 26 | response = sg.client.suppression.blocks.delete(request_body: data) 27 | puts response.status_code 28 | puts response.body 29 | puts response.headers 30 | 31 | ################################################## 32 | # Retrieve a specific block # 33 | # GET /suppression/blocks/{email} # 34 | 35 | email = 'test_url_param' 36 | response = sg.client.suppression.blocks._(email).get 37 | puts response.status_code 38 | puts response.body 39 | puts response.headers 40 | 41 | ################################################## 42 | # Delete a specific block # 43 | # DELETE /suppression/blocks/{email} # 44 | 45 | email = 'test_url_param' 46 | response = sg.client.suppression.blocks._(email).delete 47 | puts response.status_code 48 | puts response.body 49 | puts response.headers 50 | 51 | ################################################## 52 | # Retrieve all bounces # 53 | # GET /suppression/bounces # 54 | 55 | params = JSON.parse('{"start_time": 1, "end_time": 1}') 56 | response = sg.client.suppression.bounces.get(query_params: params) 57 | puts response.status_code 58 | puts response.body 59 | puts response.headers 60 | 61 | ################################################## 62 | # Delete bounces # 63 | # DELETE /suppression/bounces # 64 | 65 | data = JSON.parse('{ 66 | "delete_all": true, 67 | "emails": [ 68 | "example@example.com", 69 | "example2@example.com" 70 | ] 71 | }') 72 | response = sg.client.suppression.bounces.delete(request_body: data) 73 | puts response.status_code 74 | puts response.body 75 | puts response.headers 76 | 77 | ################################################## 78 | # Retrieve a Bounce # 79 | # GET /suppression/bounces/{email} # 80 | 81 | email = 'test_url_param' 82 | response = sg.client.suppression.bounces._(email).get 83 | puts response.status_code 84 | puts response.body 85 | puts response.headers 86 | 87 | ################################################## 88 | # Delete a bounce # 89 | # DELETE /suppression/bounces/{email} # 90 | 91 | params = JSON.parse('{"email_address": "example@example.com"}') 92 | email = 'test_url_param' 93 | response = sg.client.suppression.bounces._(email).delete(query_params: params) 94 | puts response.status_code 95 | puts response.body 96 | puts response.headers 97 | 98 | ################################################## 99 | # Retrieve all invalid emails # 100 | # GET /suppression/invalid_emails # 101 | 102 | params = JSON.parse('{"start_time": 1, "limit": 1, "end_time": 1, "offset": 1}') 103 | response = sg.client.suppression.invalid_emails.get(query_params: params) 104 | puts response.status_code 105 | puts response.body 106 | puts response.headers 107 | 108 | ################################################## 109 | # Delete invalid emails # 110 | # DELETE /suppression/invalid_emails # 111 | 112 | data = JSON.parse('{ 113 | "delete_all": false, 114 | "emails": [ 115 | "example1@example.com", 116 | "example2@example.com" 117 | ] 118 | }') 119 | response = sg.client.suppression.invalid_emails.delete(request_body: data) 120 | puts response.status_code 121 | puts response.body 122 | puts response.headers 123 | 124 | ################################################## 125 | # Retrieve a specific invalid email # 126 | # GET /suppression/invalid_emails/{email} # 127 | 128 | email = 'test_url_param' 129 | response = sg.client.suppression.invalid_emails._(email).get 130 | puts response.status_code 131 | puts response.body 132 | puts response.headers 133 | 134 | ################################################## 135 | # Delete a specific invalid email # 136 | # DELETE /suppression/invalid_emails/{email} # 137 | 138 | email = 'test_url_param' 139 | response = sg.client.suppression.invalid_emails._(email).delete 140 | puts response.status_code 141 | puts response.body 142 | puts response.headers 143 | 144 | ################################################## 145 | # Retrieve a specific spam report # 146 | # GET /suppression/spam_report/{email} # 147 | 148 | email = 'test_url_param' 149 | response = sg.client.suppression.spam_report._(email).get 150 | puts response.status_code 151 | puts response.body 152 | puts response.headers 153 | 154 | ################################################## 155 | # Delete a specific spam report # 156 | # DELETE /suppression/spam_report/{email} # 157 | 158 | email = 'test_url_param' 159 | response = sg.client.suppression.spam_reports._(email).delete 160 | puts response.status_code 161 | puts response.body 162 | puts response.headers 163 | 164 | ################################################## 165 | # Retrieve all spam reports # 166 | # GET /suppression/spam_reports # 167 | 168 | params = JSON.parse('{"start_time": 1, "limit": 1, "end_time": 1, "offset": 1}') 169 | response = sg.client.suppression.spam_reports.get(query_params: params) 170 | puts response.status_code 171 | puts response.body 172 | puts response.headers 173 | 174 | ################################################## 175 | # Delete spam reports # 176 | # DELETE /suppression/spam_reports # 177 | 178 | data = JSON.parse('{ 179 | "delete_all": false, 180 | "emails": [ 181 | "example1@example.com", 182 | "example2@example.com" 183 | ] 184 | }') 185 | response = sg.client.suppression.spam_reports.delete(request_body: data) 186 | puts response.status_code 187 | puts response.body 188 | puts response.headers 189 | 190 | ################################################## 191 | # Retrieve all global suppressions # 192 | # GET /suppression/unsubscribes # 193 | 194 | params = JSON.parse('{"start_time": 1, "limit": 1, "end_time": 1, "offset": 1}') 195 | response = sg.client.suppression.unsubscribes.get(query_params: params) 196 | puts response.status_code 197 | puts response.body 198 | puts response.headers 199 | -------------------------------------------------------------------------------- /examples/templates/templates.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Create a transactional template. # 7 | # POST /templates # 8 | 9 | data = JSON.parse('{ 10 | "name": "example_name" 11 | }') 12 | response = sg.client.templates.post(request_body: data) 13 | puts response.status_code 14 | puts response.body 15 | puts response.headers 16 | 17 | ################################################## 18 | # Retrieve all transactional templates (legacy & dynamic). # 19 | # GET /templates # 20 | 21 | params = JSON.parse('{"generations": "legacy,dynamic"}') 22 | response = sg.client.templates.get(query_params: params) 23 | puts response.status_code 24 | puts response.body 25 | puts response.headers 26 | 27 | ################################################## 28 | # Edit a transactional template. # 29 | # PATCH /templates/{template_id} # 30 | 31 | data = JSON.parse('{ 32 | "name": "new_example_name" 33 | }') 34 | template_id = 'test_url_param' 35 | response = sg.client.templates._(template_id).patch(request_body: data) 36 | puts response.status_code 37 | puts response.body 38 | puts response.headers 39 | 40 | ################################################## 41 | # Retrieve a single transactional template. # 42 | # GET /templates/{template_id} # 43 | 44 | template_id = 'test_url_param' 45 | response = sg.client.templates._(template_id).get 46 | puts response.status_code 47 | puts response.body 48 | puts response.headers 49 | 50 | ################################################## 51 | # Delete a template. # 52 | # DELETE /templates/{template_id} # 53 | 54 | template_id = 'test_url_param' 55 | response = sg.client.templates._(template_id).delete 56 | puts response.status_code 57 | puts response.body 58 | puts response.headers 59 | 60 | ################################################## 61 | # Create a new transactional template version. # 62 | # POST /templates/{template_id}/versions # 63 | 64 | data = JSON.parse('{ 65 | "active": 1, 66 | "html_content": "<%body%>", 67 | "name": "example_version_name", 68 | "plain_content": "<%body%>", 69 | "subject": "<%subject%>", 70 | "template_id": "ddb96bbc-9b92-425e-8979-99464621b543" 71 | }') 72 | template_id = 'test_url_param' 73 | response = sg.client.templates._(template_id).versions.post(request_body: data) 74 | puts response.status_code 75 | puts response.body 76 | puts response.headers 77 | 78 | ################################################## 79 | # Edit a transactional template version. # 80 | # PATCH /templates/{template_id}/versions/{version_id} # 81 | 82 | data = JSON.parse('{ 83 | "active": 1, 84 | "html_content": "<%body%>", 85 | "name": "updated_example_name", 86 | "plain_content": "<%body%>", 87 | "subject": "<%subject%>" 88 | }') 89 | template_id = 'test_url_param' 90 | version_id = 'test_url_param' 91 | response = sg.client.templates._(template_id).versions._(version_id).patch(request_body: data) 92 | puts response.status_code 93 | puts response.body 94 | puts response.headers 95 | 96 | ################################################## 97 | # Retrieve a specific transactional template version. # 98 | # GET /templates/{template_id}/versions/{version_id} # 99 | 100 | template_id = 'test_url_param' 101 | version_id = 'test_url_param' 102 | response = sg.client.templates._(template_id).versions._(version_id).get 103 | puts response.status_code 104 | puts response.body 105 | puts response.headers 106 | 107 | ################################################## 108 | # Delete a transactional template version. # 109 | # DELETE /templates/{template_id}/versions/{version_id} # 110 | 111 | template_id = 'test_url_param' 112 | version_id = 'test_url_param' 113 | response = sg.client.templates._(template_id).versions._(version_id).delete 114 | puts response.status_code 115 | puts response.body 116 | puts response.headers 117 | 118 | ################################################## 119 | # Activate a transactional template version. # 120 | # POST /templates/{template_id}/versions/{version_id}/activate # 121 | 122 | template_id = 'test_url_param' 123 | version_id = 'test_url_param' 124 | response = sg.client.templates._(template_id).versions._(version_id).activate.post 125 | puts response.status_code 126 | puts response.body 127 | puts response.headers 128 | -------------------------------------------------------------------------------- /examples/trackingsettings/trackingsettings.rb: -------------------------------------------------------------------------------- 1 | require 'sendgrid-ruby' 2 | 3 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 4 | 5 | ################################################## 6 | # Retrieve Tracking Settings # 7 | # GET /tracking_settings # 8 | 9 | params = JSON.parse('{"limit": 1, "offset": 1}') 10 | response = sg.client.tracking_settings.get(query_params: params) 11 | puts response.status_code 12 | puts response.body 13 | puts response.headers 14 | 15 | ################################################## 16 | # Update Click Tracking Settings # 17 | # PATCH /tracking_settings/click # 18 | 19 | data = JSON.parse('{ 20 | "enabled": true 21 | }') 22 | response = sg.client.tracking_settings.click.patch(request_body: data) 23 | puts response.status_code 24 | puts response.body 25 | puts response.headers 26 | 27 | ################################################## 28 | # Retrieve Click Track Settings # 29 | # GET /tracking_settings/click # 30 | 31 | response = sg.client.tracking_settings.click.get 32 | puts response.status_code 33 | puts response.body 34 | puts response.headers 35 | 36 | ################################################## 37 | # Update Google Analytics Settings # 38 | # PATCH /tracking_settings/google_analytics # 39 | 40 | data = JSON.parse('{ 41 | "enabled": true, 42 | "utm_campaign": "website", 43 | "utm_content": "", 44 | "utm_medium": "email", 45 | "utm_source": "sendgrid.com", 46 | "utm_term": "" 47 | }') 48 | response = sg.client.tracking_settings.google_analytics.patch(request_body: data) 49 | puts response.status_code 50 | puts response.body 51 | puts response.headers 52 | 53 | ################################################## 54 | # Retrieve Google Analytics Settings # 55 | # GET /tracking_settings/google_analytics # 56 | 57 | response = sg.client.tracking_settings.google_analytics.get 58 | puts response.status_code 59 | puts response.body 60 | puts response.headers 61 | 62 | ################################################## 63 | # Update Open Tracking Settings # 64 | # PATCH /tracking_settings/open # 65 | 66 | data = JSON.parse('{ 67 | "enabled": true 68 | }') 69 | response = sg.client.tracking_settings.open.patch(request_body: data) 70 | puts response.status_code 71 | puts response.body 72 | puts response.headers 73 | 74 | ################################################## 75 | # Get Open Tracking Settings # 76 | # GET /tracking_settings/open # 77 | 78 | response = sg.client.tracking_settings.open.get 79 | puts response.status_code 80 | puts response.body 81 | puts response.headers 82 | 83 | ################################################## 84 | # Update Subscription Tracking Settings # 85 | # PATCH /tracking_settings/subscription # 86 | 87 | data = JSON.parse('{ 88 | "enabled": true, 89 | "html_content": "html content", 90 | "landing": "landing page html", 91 | "plain_content": "text content", 92 | "replace": "replacement tag", 93 | "url": "url" 94 | }') 95 | response = sg.client.tracking_settings.subscription.patch(request_body: data) 96 | puts response.status_code 97 | puts response.body 98 | puts response.headers 99 | 100 | ################################################## 101 | # Retrieve Subscription Tracking Settings # 102 | # GET /tracking_settings/subscription # 103 | 104 | response = sg.client.tracking_settings.subscription.get 105 | puts response.status_code 106 | puts response.body 107 | puts response.headers 108 | -------------------------------------------------------------------------------- /gemfiles/Sinatra_1.gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'ruby_http_client' 6 | gem 'sinatra', '~> 1.4' 7 | -------------------------------------------------------------------------------- /gemfiles/Sinatra_2.gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'ruby_http_client' 6 | gem 'sinatra', '>= 2.0.0.rc2' 7 | -------------------------------------------------------------------------------- /lib/rack/sendgrid_webhook_verification.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Rack 4 | # Middleware that verifies webhooks from SendGrid using the EventWebhook 5 | # verifier. 6 | # 7 | # The middleware takes a public key with which to set up the request 8 | # validator and any number of paths. When a path matches the incoming request 9 | # path, the request will be verified using the signature and timestamp of the 10 | # request. 11 | # 12 | # Example: 13 | # 14 | # require 'rack' 15 | # use Rack::SendGridWebhookVerification, ENV['PUBLIC_KEY'], /\/emails/ 16 | # 17 | # The above appends this middleware to the stack, using a public key saved in 18 | # the ENV and only against paths that match /\/emails/. If the request 19 | # validates then it gets passed on to the action as normal. If the request 20 | # doesn't validate then the middleware responds immediately with a 403 status. 21 | class SendGridWebhookVerification 22 | def initialize(app, public_key, *paths) 23 | @app = app 24 | @public_key = public_key 25 | @path_regex = Regexp.union(paths) 26 | end 27 | 28 | def call(env) 29 | return @app.call(env) unless env['PATH_INFO'].match(@path_regex) 30 | 31 | request = Rack::Request.new(env) 32 | 33 | event_webhook = SendGrid::EventWebhook.new 34 | ec_public_key = event_webhook.convert_public_key_to_ecdsa(@public_key) 35 | verified = event_webhook.verify_signature( 36 | ec_public_key, 37 | request.body.read, 38 | request.env[SendGrid::EventWebhookHeader::SIGNATURE], 39 | request.env[SendGrid::EventWebhookHeader::TIMESTAMP] 40 | ) 41 | 42 | request.body.rewind 43 | 44 | if verified 45 | @app.call(env) 46 | else 47 | [ 48 | 403, 49 | { 'Content-Type' => 'text/plain' }, 50 | ['SendGrid Request Verification Failed.'] 51 | ] 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/sendgrid-ruby.rb: -------------------------------------------------------------------------------- 1 | require_relative 'sendgrid/base_interface' 2 | require_relative 'sendgrid/sendgrid' 3 | require_relative 'sendgrid/twilio_email' 4 | require_relative 'sendgrid/version' 5 | require_relative 'sendgrid/helpers/eventwebhook/eventwebhook' 6 | require_relative 'sendgrid/helpers/ip_management/ip_management' 7 | require_relative 'sendgrid/helpers/mail/asm' 8 | require_relative 'sendgrid/helpers/mail/attachment' 9 | require_relative 'sendgrid/helpers/mail/bcc_settings' 10 | require_relative 'sendgrid/helpers/mail/bypass_list_management' 11 | require_relative 'sendgrid/helpers/mail/category' 12 | require_relative 'sendgrid/helpers/mail/click_tracking' 13 | require_relative 'sendgrid/helpers/mail/content' 14 | require_relative 'sendgrid/helpers/mail/custom_arg' 15 | require_relative 'sendgrid/helpers/mail/email' 16 | require_relative 'sendgrid/helpers/mail/footer' 17 | require_relative 'sendgrid/helpers/mail/ganalytics' 18 | require_relative 'sendgrid/helpers/mail/header' 19 | require_relative 'sendgrid/helpers/mail/mail' 20 | require_relative 'sendgrid/helpers/mail/mail_settings' 21 | require_relative 'sendgrid/helpers/mail/open_tracking' 22 | require_relative 'sendgrid/helpers/mail/personalization' 23 | require_relative 'sendgrid/helpers/mail/section' 24 | require_relative 'sendgrid/helpers/mail/spam_check' 25 | require_relative 'sendgrid/helpers/mail/subscription_tracking' 26 | require_relative 'sendgrid/helpers/mail/substitution' 27 | require_relative 'sendgrid/helpers/mail/tracking_settings' 28 | require_relative 'sendgrid/helpers/settings/settings' 29 | require_relative 'sendgrid/helpers/stats/email_stats' 30 | require_relative 'sendgrid/helpers/stats/stats_response' 31 | require_relative 'sendgrid/helpers/stats/metrics' 32 | require_relative 'sendgrid/helpers/permissions/scope' 33 | require_relative 'rack/sendgrid_webhook_verification' 34 | -------------------------------------------------------------------------------- /lib/sendgrid/base_interface.rb: -------------------------------------------------------------------------------- 1 | require 'ruby_http_client' 2 | require_relative 'version' 3 | 4 | # Initialize the HTTP client 5 | class BaseInterface 6 | attr_accessor :client 7 | attr_reader :request_headers, :host, :version, :impersonate_subuser, :http_options 8 | 9 | # * *Args* : 10 | # - +auth+ -> authorization header value 11 | # - +host+ -> the base URL for the API 12 | # - +request_headers+ -> any headers that you want to be globally applied 13 | # - +version+ -> the version of the API you wish to access, 14 | # currently only "v3" is supported 15 | # - +impersonate_subuser+ -> the subuser to impersonate, will be passed 16 | # in the "On-Behalf-Of" header 17 | # - +http_options+ -> http options that you want to be globally applied to each request 18 | # 19 | def initialize(auth:, host:, request_headers: nil, version: nil, impersonate_subuser: nil, http_options: {}) 20 | @auth = auth 21 | @host = host 22 | @version = version || 'v3' 23 | @impersonate_subuser = impersonate_subuser 24 | @user_agent = "sendgrid/#{SendGrid::VERSION};ruby" 25 | @request_headers = JSON.parse(' 26 | { 27 | "Authorization": "' + @auth + '", 28 | "Accept": "application/json", 29 | "User-Agent": "' + @user_agent + '" 30 | } 31 | ') 32 | @request_headers['On-Behalf-Of'] = @impersonate_subuser if @impersonate_subuser 33 | 34 | @request_headers = @request_headers.merge(request_headers) if request_headers 35 | @http_options = http_options 36 | @client = SendGrid::Client.new(host: "#{@host}/#{@version}", 37 | request_headers: @request_headers, 38 | http_options: @http_options) 39 | end 40 | 41 | # Client libraries contain setters for specifying region/edge. 42 | # This supports global and eu regions only. This set will likely expand in the future. 43 | # Global is the default residency (or region) 44 | # Global region means the message will be sent through https://api.sendgrid.com 45 | # EU region means the message will be sent through https://api.eu.sendgrid.com 46 | # Parameters: 47 | # - region(String) : specify the region. Currently supports "global" and "eu" 48 | def sendgrid_data_residency(region:) 49 | region_host_dict = { "eu" => 'https://api.eu.sendgrid.com', "global" => 'https://api.sendgrid.com' } 50 | raise ArgumentError, "region can only be \"eu\" or \"global\"" if region.nil? || !region_host_dict.key?(region) 51 | 52 | @host = region_host_dict[region] 53 | @client = SendGrid::Client.new(host: "#{@host}/#{@version}", 54 | request_headers: @request_headers, 55 | http_options: @http_options) 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/eventwebhook/eventwebhook.rb: -------------------------------------------------------------------------------- 1 | require 'base64' 2 | require 'digest' 3 | require 'openssl' 4 | 5 | module SendGrid 6 | # This class allows you to use the Event Webhook feature. Read the docs for 7 | # more details: https://sendgrid.com/docs/for-developers/tracking-events/event 8 | class EventWebhook 9 | # * *Args* : 10 | # - +public_key+ -> verification key under Mail Settings 11 | # 12 | def convert_public_key_to_ecdsa(public_key) 13 | verify_engine 14 | OpenSSL::PKey::EC.new(Base64.decode64(public_key)) 15 | end 16 | 17 | # * *Args* : 18 | # - +public_key+ -> elliptic curve public key 19 | # - +payload+ -> event payload in the request body 20 | # - +signature+ -> signature value obtained from the 'X-Twilio-Email-Event-Webhook-Signature' header 21 | # - +timestamp+ -> timestamp value obtained from the 'X-Twilio-Email-Event-Webhook-Timestamp' header 22 | def verify_signature(public_key, payload, signature, timestamp) 23 | verify_engine 24 | timestamped_playload = "#{timestamp}#{payload}" 25 | payload_digest = Digest::SHA256.digest(timestamped_playload) 26 | decoded_signature = Base64.decode64(signature) 27 | public_key.dsa_verify_asn1(payload_digest, decoded_signature) 28 | rescue StandardError 29 | false 30 | end 31 | 32 | def verify_engine 33 | # JRuby does not fully support ECDSA: https://github.com/jruby/jruby-openssl/issues/193 34 | raise NotSupportedError, "Event Webhook verification is not supported by JRuby" if RUBY_PLATFORM == "java" 35 | end 36 | 37 | class Error < ::RuntimeError 38 | end 39 | 40 | class NotSupportedError < Error 41 | end 42 | end 43 | 44 | # This class lists headers that get posted to the webhook. Read the docs for 45 | # more details: https://sendgrid.com/docs/for-developers/tracking-events/event 46 | class EventWebhookHeader 47 | SIGNATURE = "HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_SIGNATURE".freeze 48 | TIMESTAMP = "HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_TIMESTAMP".freeze 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/inbound/README.md: -------------------------------------------------------------------------------- 1 | **This helper is a stand alone module to help get you started consuming and processing Inbound Parse data.** 2 | 3 | ## Table of Contents 4 | 5 | - [Installation](#installation) 6 | - [Quick Start for Local Testing with Sample Data](#quick-start-for-local-testing-with-sample-data) 7 | - [Quick Start for Local Testing with Real Data](#quick-start-for-local-testing-with-real-data) 8 | - [Code Walkthrough](#code-walkthrough) 9 | - [app.rb](#apprb) 10 | - [config.yml](#configyml) 11 | - [send.rb & /sample_data](#sendrb--sampledata) 12 | - [Contributing](#contributing) 13 | 14 | 15 | 16 | 17 | # Installation 18 | 19 | In addition to the installation instructions in 20 | [the main readme](../../../../README.md#installation), 21 | you must also add sinatra to your Gemfile: 22 | 23 | ``` 24 | gem 'sinatra', '>= 1.4.7', '< 3' 25 | ``` 26 | 27 | 28 | # Quick Start for Local Testing with Sample Data 29 | 30 | ```bash 31 | git clone https://github.com/sendgrid/sendgrid-ruby.git 32 | cd sendgrid-ruby 33 | bundle install 34 | ``` 35 | 36 | Run the Inbound Parse listener in your terminal: 37 | 38 | ```ruby 39 | rackup 40 | ``` 41 | 42 | In another terminal, run the test data sender: 43 | 44 | ```bash 45 | cd [path to sendgrid-ruby] 46 | bundle install 47 | ruby ./lib/sendgrid/helpers/inbound/send.rb ./lib/sendgrid/helpers/inbound/sample_data/default_data.txt 48 | ``` 49 | 50 | More sample data can be found [here](sample_data). 51 | 52 | View the results in the first terminal. 53 | 54 | 55 | # Quick Start for Local Testing with Real Data 56 | 57 | [Setup your MX records.](https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Setup) Depending on your domain name host, you may need to wait up to 48 hours for the settings to propagate. 58 | 59 | Run the Inbound Parse listener in your terminal: 60 | 61 | ```bash 62 | git clone https://github.com/sendgrid/sendgrid-ruby.git 63 | cd sendgrid-ruby 64 | bundle install 65 | rackup 66 | ``` 67 | 68 | In another terminal, use [ngrok](https://ngrok.com/) to allow external access to your machine: 69 | ```bash 70 | ngrok http 9292 71 | ``` 72 | 73 | Update your Twilio SendGrid Incoming Parse settings: [Settings Page](https://app.sendgrid.com/settings/parse) | [Docs](https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Pointing-to-a-Hostname-and-URL) 74 | 75 | - For the HOSTNAME field, use the domain that you changed the MX records (e.g. inbound.yourdomain.com) 76 | - For the URL field, use the URL generated by ngrok + /inbound, e.g http://XXXXXXX.ngrok.io/inbound 77 | 78 | Next, send an email to [anything]@inbound.yourdomain.com, then look at the terminal where you started the Inbound Parse listener. 79 | 80 | 81 | # Code Walkthrough 82 | 83 | ## app.rb 84 | 85 | This module runs a [Sinatra](http://www.sinatrarb.com/) server, that by default (you can change those settings [here](config.yml)), listens for POSTs on http://localhost:9292. When the server receives the POST, it parses and prints the key/value data. 86 | 87 | ## config.yml 88 | 89 | This module loads application environment variables (located in [config.yml](config.yml)). 90 | 91 | ## send.rb & /sample_data 92 | 93 | This module is used to send sample test data. It is useful for testing and development, particularly while you wait for your MX records to propagate. 94 | 95 | 96 | # Contributing 97 | 98 | If you would like to contribute to this project, please see our [contributing guide](../../../../CONTRIBUTING.md). Thanks! 99 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/inbound/app.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require 'sinatra' 3 | rescue LoadError 4 | puts <<-NOTE 5 | As of sengrid verison 6, sinatra is no longer specified as a dependency of 6 | the sendgrid gem. All the functionality of the inbound server is still the same 7 | and fully supported, but you just need to include the sinatra dependency in your gemfile 8 | yourself, like so: 9 | 10 | gem 'sinatra', '>= 1.4.7', '< 3' 11 | NOTE 12 | raise 13 | end 14 | require 'logger' 15 | require 'json' 16 | require 'yaml' 17 | 18 | class Main < Sinatra::Base 19 | configure :production, :development do 20 | enable :logging 21 | set :config, YAML.load_file("#{File.dirname(__FILE__)}/config.yml") 22 | end 23 | 24 | get '/' do 25 | redirect to('index.html') 26 | end 27 | 28 | post settings.config['endpoint'] do 29 | filtered = params.select { |k, _v| settings.config['keys'].include?(k) } 30 | logger.info JSON.pretty_generate(filtered) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/inbound/config.yml: -------------------------------------------------------------------------------- 1 | # Incoming Parse endpoint for receiver 2 | endpoint: '/inbound' 3 | 4 | # List all Incoming Parse fields you would like parsed 5 | # Reference: https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html 6 | keys: 7 | - from 8 | - attachments 9 | - headers 10 | - text 11 | - envelope 12 | - to 13 | - html 14 | - sender_ip 15 | - attachment-info 16 | - subject 17 | - dkim 18 | - SPF 19 | - charsets 20 | - content-ids 21 | - spam_report 22 | - spam_score 23 | - email 24 | 25 | # URL that the sender will POST to 26 | host: 'http://127.0.0.1:9292/inbound' 27 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/inbound/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Twilio SendGrid Incoming Parse 4 | 5 | 6 |

You have successfuly launched the server!

7 | 8 | Check out the documentation on how to use this software to utilize the SendGrid Inbound Parse webhook. 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/inbound/sample_data/default_data.txt: -------------------------------------------------------------------------------- 1 | --xYzZY 2 | Content-Disposition: form-data; name="headers" 3 | 4 | MIME-Version: 1.0 5 | Received: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 18:10:13 -0700 (PDT) 6 | From: Example User 7 | Date: Wed, 10 Aug 2016 18:10:13 -0700 8 | Subject: Inbound Parse Test Data 9 | To: inbound@inbound.example.com 10 | Content-Type: multipart/alternative; boundary=001a113df448cad2d00539c16e89 11 | 12 | --xYzZY 13 | Content-Disposition: form-data; name="dkim" 14 | 15 | {@sendgrid.com : pass} 16 | --xYzZY 17 | Content-Disposition: form-data; name="to" 18 | 19 | inbound@inbound.example.com 20 | --xYzZY 21 | Content-Disposition: form-data; name="html" 22 | 23 | Hello Twilio SendGrid! 24 | 25 | --xYzZY 26 | Content-Disposition: form-data; name="from" 27 | 28 | Example User 29 | --xYzZY 30 | Content-Disposition: form-data; name="text" 31 | 32 | Hello Twilio SendGrid! 33 | 34 | --xYzZY 35 | Content-Disposition: form-data; name="sender_ip" 36 | 37 | 0.0.0.0 38 | --xYzZY 39 | Content-Disposition: form-data; name="envelope" 40 | 41 | {"to":["inbound@inbound.example.com"],"from":"test@example.com"} 42 | --xYzZY 43 | Content-Disposition: form-data; name="attachments" 44 | 45 | 0 46 | --xYzZY 47 | Content-Disposition: form-data; name="subject" 48 | 49 | Testing non-raw 50 | --xYzZY 51 | Content-Disposition: form-data; name="charsets" 52 | 53 | {"to":"UTF-8","html":"UTF-8","subject":"UTF-8","from":"UTF-8","text":"UTF-8"} 54 | --xYzZY 55 | Content-Disposition: form-data; name="SPF" 56 | 57 | pass 58 | --xYzZY-- 59 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/inbound/sample_data/raw_data.txt: -------------------------------------------------------------------------------- 1 | --xYzZY 2 | Content-Disposition: form-data; name="dkim" 3 | 4 | {@sendgrid.com : pass} 5 | --xYzZY 6 | Content-Disposition: form-data; name="email" 7 | 8 | MIME-Version: 1.0 9 | Received: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 14:44:21 -0700 (PDT) 10 | From: Example User 11 | Date: Wed, 10 Aug 2016 14:44:21 -0700 12 | Subject: Inbound Parse Test Raw Data 13 | To: inbound@inbound.inbound.com 14 | Content-Type: multipart/alternative; boundary=001a113ee97c89842f0539be8e7a 15 | 16 | --001a113ee97c89842f0539be8e7a 17 | Content-Type: text/plain; charset=UTF-8 18 | 19 | Hello Twilio SendGrid! 20 | 21 | --001a113ee97c89842f0539be8e7a 22 | Content-Type: text/html; charset=UTF-8 23 | Content-Transfer-Encoding: quoted-printable 24 | 25 | Hello Twilio SendGrid! 26 | 27 | --001a113ee97c89842f0539be8e7a-- 28 | 29 | --xYzZY 30 | Content-Disposition: form-data; name="to" 31 | 32 | inbound@inbound.inbound.com 33 | --xYzZY 34 | Content-Disposition: form-data; name="from" 35 | 36 | Example User 37 | --xYzZY 38 | Content-Disposition: form-data; name="sender_ip" 39 | 40 | 0.0.0.0 41 | --xYzZY 42 | Content-Disposition: form-data; name="envelope" 43 | 44 | {"to":["inbound@inbound.inbound.com"],"from":"test@example.com"} 45 | --xYzZY 46 | Content-Disposition: form-data; name="subject" 47 | 48 | Testing with Request.bin 49 | --xYzZY 50 | Content-Disposition: form-data; name="charsets" 51 | 52 | {"to":"UTF-8","subject":"UTF-8","from":"UTF-8"} 53 | --xYzZY 54 | Content-Disposition: form-data; name="SPF" 55 | 56 | pass 57 | --xYzZY-- 58 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/inbound/send.rb: -------------------------------------------------------------------------------- 1 | # A module for sending test Twilio SendGrid Inbound Parse messages 2 | # Usage: ruby ./send.rb [path to file containing test data] 3 | require 'ruby_http_client' 4 | require 'yaml' 5 | require 'optparse' 6 | 7 | OPTS = {}.freeze 8 | opt = OptionParser.new 9 | opt.on('--host=HOST') { |v| OPTS[:host] = v } 10 | argv = opt.parse!(ARGV) 11 | config = YAML.load_file("#{File.dirname(__FILE__)}/config.yml") 12 | host = OPTS[:host] || config['host'] 13 | client = SendGrid::Client.new(host: host) 14 | File.open(argv[0]) do |file| 15 | data = file.read 16 | headers = { 17 | 'User-Agent' => 'Twilio-SendGrid-Test', 18 | 'Content-Type' => 'multipart/form-data; boundary=xYzZY' 19 | } 20 | response = client.post( 21 | request_body: data, request_headers: headers 22 | ) 23 | puts response.status_code 24 | puts response.body 25 | puts response.headers 26 | end 27 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/ip_management/ip_management.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class IpManagement 5 | attr_accessor :sendgrid_client 6 | 7 | def initialize(sendgrid_client:) 8 | @sendgrid_client = sendgrid_client 9 | end 10 | 11 | def unassigned 12 | response = @sendgrid_client.ips.get 13 | ips = JSON.parse(response.body) 14 | ips.select { |ip| ip.subusers.empty? } 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/README.md: -------------------------------------------------------------------------------- 1 | **This helper allows you to quickly and easily build a Mail object for sending email through Twilio SendGrid.** 2 | 3 | # Quick Start 4 | 5 | Run the [example](../../../../examples/helpers/mail) (make sure you have set your environment variable to include your SENDGRID_API_KEY). 6 | 7 | ```bash 8 | ruby examples/helpers/mail/example.rb 9 | ``` 10 | 11 | ## Usage 12 | 13 | - See the [example](../../../../examples/helpers/mail) for a complete working example. 14 | - [Documentation](https://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/index.html) 15 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/asm.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class ASM 5 | attr_accessor :group_id, :groups_to_display 6 | 7 | def initialize(group_id: nil, groups_to_display: nil) 8 | @group_id = group_id 9 | @groups_to_display = groups_to_display 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'group_id' => group_id, 15 | 'groups_to_display' => groups_to_display 16 | }.delete_if { |_, value| value.to_s.strip == '' } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/attachment.rb: -------------------------------------------------------------------------------- 1 | require 'base64' 2 | 3 | module SendGrid 4 | class Attachment 5 | attr_accessor :type, :filename, :disposition, :content_id 6 | 7 | def initialize 8 | @content = nil 9 | @type = nil 10 | @filename = nil 11 | @disposition = nil 12 | @content_id = nil 13 | end 14 | 15 | def content=(content) 16 | @encoded_content = nil 17 | @content = content 18 | end 19 | 20 | def content 21 | return @encoded_content if @encoded_content 22 | 23 | @encoded_content = if @content.respond_to?(:read) 24 | encode @content 25 | else 26 | @content 27 | end 28 | end 29 | 30 | def to_json(*) 31 | { 32 | 'content' => content, 33 | 'type' => type, 34 | 'filename' => filename, 35 | 'disposition' => disposition, 36 | 'content_id' => content_id 37 | }.delete_if { |_, value| value.to_s.strip == '' } 38 | end 39 | 40 | private 41 | 42 | def encode(io) 43 | str = io.read 44 | # Since the API expects UTF-8, we need to ensure that we're 45 | # converting other formats to it so (byte-wise) Base64 encoding 46 | # will come through properly on the other side. 47 | # 48 | # Not much to be done to try to handle encoding for files opened 49 | # in binary mode, but at least we can faithfully convey the 50 | # bytes. 51 | str = str.encode('UTF-8') unless io.respond_to?(:binmode?) && io.binmode? 52 | Base64.encode64 str 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/bcc_settings.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class BccSettings 5 | attr_accessor :enable, :email 6 | 7 | def initialize(enable: nil, email: nil) 8 | @enable = enable 9 | @email = email 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'enable' => enable, 15 | 'email' => email 16 | }.delete_if { |_, value| value.to_s.strip == '' } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/bypass_list_management.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class BypassListManagement 5 | attr_accessor :enable 6 | 7 | def initialize(enable: nil) 8 | @enable = enable 9 | end 10 | 11 | def to_json(*) 12 | { 13 | 'enable' => enable 14 | }.delete_if { |_, value| value.to_s.strip == '' } 15 | end 16 | end 17 | 18 | class SandBoxMode 19 | attr_accessor :enable 20 | 21 | def initialize(enable: nil) 22 | @enable = enable 23 | end 24 | 25 | def to_json(*) 26 | { 27 | 'enable' => enable 28 | }.delete_if { |_, value| value.to_s.strip == '' } 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/category.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | class Category 3 | attr_accessor :name 4 | 5 | def initialize(name: nil) 6 | @name = name 7 | end 8 | 9 | def to_json(*) 10 | { 11 | 'category' => name 12 | }.delete_if { |_, value| value.to_s.strip == '' } 13 | end 14 | 15 | alias category name 16 | alias category= name= 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/click_tracking.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class ClickTracking 5 | attr_accessor :enable, :enable_text 6 | 7 | def initialize(enable: nil, enable_text: nil) 8 | @enable = enable 9 | @enable_text = enable_text 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'enable' => enable, 15 | 'enable_text' => enable_text 16 | }.delete_if { |_, value| value.to_s.strip == '' } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/content.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Content 5 | attr_accessor :type, :value 6 | 7 | def initialize(type: nil, value: nil) 8 | @type = type 9 | @value = value 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'type' => type, 15 | 'value' => value 16 | }.delete_if { |_, value| value.to_s.strip == '' } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/custom_arg.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class CustomArg 5 | attr_accessor :custom_arg 6 | 7 | def initialize(key: nil, value: nil) 8 | @custom_arg = {} 9 | key.nil? || value.nil? ? @custom_arg = nil : @custom_arg[key.to_s] = value.to_s 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'custom_arg' => custom_arg 15 | }.delete_if { |_, value| value.to_s.strip == '' } 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/email.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Email 5 | attr_accessor :email, :name 6 | 7 | # @param [String] email required e-mail address 8 | # @param [String] name optionally personification 9 | def initialize(email:, name: nil) 10 | if name 11 | @email = email 12 | @name = name 13 | else 14 | @email, @name = split_email(email) 15 | end 16 | end 17 | 18 | def split_email(email) 19 | split = /(?:(?
.+)\s)?.+@[^>]+)>?/.match(email) 20 | raise ArgumentError, "email (#{email}) is invalid" unless split 21 | 22 | [split[:email], split[:address]] 23 | end 24 | 25 | def to_json(*) 26 | { 27 | 'email' => email, 28 | 'name' => name 29 | }.delete_if { |_, value| value.to_s.strip == '' } 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/footer.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Footer 5 | attr_accessor :enable, :text, :html 6 | 7 | def initialize(enable: nil, text: nil, html: nil) 8 | @enable = enable 9 | @text = text 10 | @html = html 11 | end 12 | 13 | def to_json(*) 14 | { 15 | 'enable' => enable, 16 | 'text' => text, 17 | 'html' => html 18 | }.delete_if { |_, value| value.to_s.strip == '' } 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/ganalytics.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Ganalytics 5 | attr_accessor :enable, :utm_source, :utm_medium, :utm_term, :utm_content, :utm_name, :utm_campaign 6 | 7 | def initialize(enable: nil, utm_source: nil, utm_medium: nil, utm_term: nil, utm_content: nil, utm_campaign: nil, utm_name: nil) 8 | @enable = enable 9 | @utm_source = utm_source 10 | @utm_medium = utm_medium 11 | @utm_term = utm_term 12 | @utm_content = utm_content 13 | @utm_campaign = utm_campaign 14 | @utm_name = utm_name 15 | end 16 | 17 | def to_json(*) 18 | { 19 | 'enable' => enable, 20 | 'utm_source' => utm_source, 21 | 'utm_medium' => utm_medium, 22 | 'utm_term' => utm_term, 23 | 'utm_content' => utm_content, 24 | 'utm_campaign' => utm_campaign 25 | }.delete_if { |_, value| value.to_s.strip == '' } 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/header.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Header 5 | attr_accessor :header 6 | 7 | def initialize(key: nil, value: nil) 8 | @header = {} 9 | key.nil? || value.nil? ? @header = nil : @header[key] = value 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'header' => header 15 | }.delete_if { |_, value| value.to_s.strip == '' } 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/mail.rb: -------------------------------------------------------------------------------- 1 | # Build the request body for the v3/mail/send endpoint 2 | # Please see the examples/helpers/mail/example.rb for a demonstration of usage 3 | require 'json' 4 | 5 | module SendGrid 6 | class Mail 7 | attr_accessor :subject, :ip_pool_name, :template_id, :send_at, :batch_id 8 | attr_reader :personalizations, :contents, :attachments, :categories, :sections, :headers, :custom_args 9 | attr_writer :from, :asm, :mail_settings, :tracking_settings, :reply_to 10 | 11 | # We allow for all nil values here to create uninitialized Mail objects 12 | # (e.g. /use-cases/transactional-templates.md) 13 | def initialize(from_email = nil, subj = nil, to_email = nil, cont = nil) # rubocop:disable Metrics/ParameterLists 14 | @from = nil 15 | @subject = nil 16 | @personalizations = [] 17 | @contents = [] 18 | @attachments = [] 19 | @template_id = nil 20 | @sections = {} 21 | @headers = {} 22 | @categories = [] 23 | @custom_args = {} 24 | @send_at = nil 25 | @batch_id = nil 26 | @asm = nil 27 | @ip_pool_name = nil 28 | @mail_settings = nil 29 | @tracking_settings = nil 30 | @reply_to = nil 31 | 32 | return if from_email.nil? && subj.nil? && to_email.nil? && cont.nil? 33 | 34 | self.from = from_email 35 | self.subject = subj 36 | personalization = Personalization.new 37 | personalization.add_to(to_email) 38 | add_personalization(personalization) 39 | add_content(cont) 40 | end 41 | 42 | def from 43 | @from.nil? ? nil : @from.to_json 44 | end 45 | 46 | def add_personalization(personalization) 47 | @personalizations << personalization.to_json 48 | end 49 | 50 | def add_content(content) 51 | @contents << content.to_json 52 | end 53 | 54 | def check_for_secrets(patterns) 55 | contents = @contents.map { |content| content['value'] }.join(' ') 56 | patterns.each do |pattern| 57 | raise SecurityError, 'Content contains sensitive information.' if contents.match(pattern) 58 | end 59 | end 60 | 61 | def add_attachment(attachment) 62 | @attachments << attachment.to_json 63 | end 64 | 65 | def add_category(category) 66 | @categories << category.name 67 | end 68 | 69 | def add_section(section) 70 | section = section.to_json 71 | @sections = @sections.merge(section['section']) 72 | end 73 | 74 | def add_header(header) 75 | header = header.to_json 76 | @headers = @headers.merge(header['header']) 77 | end 78 | 79 | def add_custom_arg(custom_arg) 80 | custom_arg = custom_arg.to_json 81 | @custom_args = @custom_args.merge(custom_arg['custom_arg']) 82 | end 83 | 84 | def asm 85 | @asm.nil? ? nil : @asm.to_json 86 | end 87 | 88 | def mail_settings 89 | @mail_settings.nil? ? nil : @mail_settings.to_json 90 | end 91 | 92 | def tracking_settings 93 | @tracking_settings.nil? ? nil : @tracking_settings.to_json 94 | end 95 | 96 | def reply_to 97 | @reply_to.nil? ? nil : @reply_to.to_json 98 | end 99 | 100 | def to_json(*) 101 | { 102 | 'from' => from, 103 | 'subject' => subject, 104 | 'personalizations' => personalizations, 105 | 'content' => contents, 106 | 'attachments' => attachments, 107 | 'template_id' => template_id, 108 | 'sections' => sections, 109 | 'headers' => headers, 110 | 'categories' => categories, 111 | 'custom_args' => custom_args, 112 | 'send_at' => send_at, 113 | 'batch_id' => batch_id, 114 | 'asm' => asm, 115 | 'ip_pool_name' => ip_pool_name, 116 | 'mail_settings' => mail_settings, 117 | 'tracking_settings' => tracking_settings, 118 | 'reply_to' => reply_to 119 | }.delete_if { |_, value| value.to_s.strip == '' || value == [] || value == {} } 120 | end 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/mail_settings.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class MailSettings 5 | attr_writer :sandbox_mode, :footer, :bcc, :spam_check, :bypass_list_management 6 | 7 | def initialize 8 | @bcc = nil 9 | @bypass_list_management = nil 10 | @footer = nil 11 | @sandbox_mode = nil 12 | @spam_check = nil 13 | end 14 | 15 | def sandbox_mode 16 | @sandbox_mode.nil? ? nil : @sandbox_mode.to_json 17 | end 18 | 19 | def bypass_list_management 20 | @bypass_list_management.nil? ? nil : @bypass_list_management.to_json 21 | end 22 | 23 | def footer 24 | @footer.nil? ? nil : @footer.to_json 25 | end 26 | 27 | def bcc 28 | @bcc.nil? ? nil : @bcc.to_json 29 | end 30 | 31 | def spam_check 32 | @spam_check.nil? ? nil : @spam_check.to_json 33 | end 34 | 35 | def to_json(*) 36 | { 37 | 'bcc' => bcc, 38 | 'bypass_list_management' => bypass_list_management, 39 | 'footer' => footer, 40 | 'sandbox_mode' => sandbox_mode, 41 | 'spam_check' => spam_check 42 | }.delete_if { |_, value| value.to_s.strip == '' } 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/open_tracking.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class OpenTracking 5 | attr_accessor :enable, :substitution_tag 6 | 7 | def initialize(enable: nil, substitution_tag: nil) 8 | @enable = enable 9 | @substitution_tag = substitution_tag 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'enable' => enable, 15 | 'substitution_tag' => substitution_tag 16 | }.delete_if { |_, value| value.to_s.strip == '' } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/personalization.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Personalization 5 | attr_reader :tos, :from, :ccs, :bccs, :headers, :substitutions, :custom_args, 6 | :dynamic_template_data 7 | 8 | attr_accessor :send_at, :subject 9 | 10 | def initialize 11 | @tos = [] 12 | @from = nil 13 | @ccs = [] 14 | @bccs = [] 15 | @subject = nil 16 | @headers = {} 17 | @substitutions = {} 18 | @custom_args = {} 19 | @dynamic_template_data = {} 20 | @send_at = nil 21 | end 22 | 23 | def add_to(to) 24 | raise DuplicatePersonalizationError if duplicate?(to) 25 | 26 | @tos << to.to_json 27 | end 28 | 29 | def add_from(from) 30 | @from = from.to_json 31 | end 32 | 33 | def add_cc(cc) 34 | raise DuplicatePersonalizationError if duplicate?(cc) 35 | 36 | @ccs << cc.to_json 37 | end 38 | 39 | def add_bcc(bcc) 40 | raise DuplicatePersonalizationError if duplicate?(bcc) 41 | 42 | @bccs << bcc.to_json 43 | end 44 | 45 | def add_header(header) 46 | header = header.to_json 47 | @headers = @headers.merge(header['header']) 48 | end 49 | 50 | def add_substitution(substitution) 51 | substitution = substitution.to_json 52 | @substitutions = @substitutions.merge(substitution['substitution']) 53 | end 54 | 55 | def add_custom_arg(custom_arg) 56 | custom_arg = custom_arg.to_json 57 | @custom_args = @custom_args.merge(custom_arg['custom_arg']) 58 | end 59 | 60 | def add_dynamic_template_data(dynamic_template_data) 61 | @dynamic_template_data.merge!(dynamic_template_data) 62 | end 63 | 64 | def to_json(*) 65 | { 66 | 'to' => tos, 67 | 'from' => from, 68 | 'cc' => ccs, 69 | 'bcc' => bccs, 70 | 'subject' => subject, 71 | 'headers' => headers, 72 | 'substitutions' => substitutions, 73 | 'custom_args' => custom_args, 74 | 'dynamic_template_data' => dynamic_template_data, 75 | 'send_at' => send_at 76 | }.delete_if { |_, value| value.to_s.strip == '' || value == [] || value == {} } 77 | end 78 | 79 | private 80 | 81 | def duplicate?(addition) 82 | additional_email = addition.email.downcase 83 | 84 | [@tos, @ccs, @bccs].flatten.each do |elm| 85 | return true if elm&.dig('email')&.downcase == additional_email 86 | end 87 | 88 | false 89 | end 90 | end 91 | 92 | class DuplicatePersonalizationError < StandardError; end 93 | end 94 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/section.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Section 5 | attr_accessor :section 6 | 7 | def initialize(key: nil, value: nil) 8 | @section = {} 9 | key.nil? || value.nil? ? @section = nil : @section[key] = value 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'section' => section 15 | }.delete_if { |_, value| value.to_s.strip == '' } 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/spam_check.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class SpamCheck 5 | attr_accessor :enable, :threshold, :post_to_url 6 | 7 | def initialize(enable: nil, threshold: nil, post_to_url: nil) 8 | @enable = enable 9 | @threshold = threshold 10 | @post_to_url = post_to_url 11 | end 12 | 13 | def to_json(*) 14 | { 15 | 'enable' => enable, 16 | 'threshold' => threshold, 17 | 'post_to_url' => post_to_url 18 | }.delete_if { |_, value| value.to_s.strip == '' } 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/subscription_tracking.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class SubscriptionTracking 5 | attr_accessor :enable, :text, :html, :substitution_tag 6 | 7 | def initialize(enable: nil, text: nil, html: nil, substitution_tag: nil) 8 | @enable = enable 9 | @text = text 10 | @html = html 11 | @substitution_tag = substitution_tag 12 | end 13 | 14 | def to_json(*) 15 | { 16 | 'enable' => enable, 17 | 'text' => text, 18 | 'html' => html, 19 | 'substitution_tag' => substitution_tag 20 | }.delete_if { |_, value| value.to_s.strip == '' } 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/substitution.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class Substitution 5 | attr_accessor :substitution 6 | 7 | def initialize(key: nil, value: nil) 8 | @substitution = {} 9 | key.nil? || value.nil? ? @substitution = nil : @substitution[key] = value 10 | end 11 | 12 | def to_json(*) 13 | { 14 | 'substitution' => substitution 15 | }.delete_if { |_, value| value.to_s.strip == '' } 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/mail/tracking_settings.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class TrackingSettings 5 | attr_writer :click_tracking, :open_tracking, :subscription_tracking, :ganalytics 6 | 7 | def initialize 8 | @click_tracking = nil 9 | @open_tracking = nil 10 | @subscription_tracking = nil 11 | @ganalytics = nil 12 | end 13 | 14 | def click_tracking 15 | @click_tracking.nil? ? nil : @click_tracking.to_json 16 | end 17 | 18 | def open_tracking 19 | @open_tracking.nil? ? nil : @open_tracking.to_json 20 | end 21 | 22 | def subscription_tracking 23 | @subscription_tracking.nil? ? nil : @subscription_tracking.to_json 24 | end 25 | 26 | def ganalytics 27 | @ganalytics.nil? ? nil : @ganalytics.to_json 28 | end 29 | 30 | def to_json(*) 31 | { 32 | 'click_tracking' => click_tracking, 33 | 'open_tracking' => open_tracking, 34 | 'subscription_tracking' => subscription_tracking, 35 | 'ganalytics' => ganalytics 36 | }.delete_if { |_, value| value.to_s.strip == '' } 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/permissions/scope.rb: -------------------------------------------------------------------------------- 1 | # This is used for getting scopes 2 | require 'yaml' 3 | 4 | module SendGrid 5 | class Scope 6 | SCOPES = YAML.load_file("#{File.dirname(__FILE__)}/scopes.yml").freeze 7 | 8 | class << self 9 | def admin_permissions 10 | SCOPES.values.map(&:values).flatten 11 | end 12 | 13 | def read_only_permissions 14 | SCOPES.map { |_, v| v[:read] }.flatten 15 | end 16 | 17 | SCOPES.each_key do |endpoint| 18 | define_method "#{endpoint}_read_only_permissions" do 19 | SCOPES[endpoint][:read] 20 | end 21 | 22 | define_method "#{endpoint}_full_access_permissions" do 23 | SCOPES[endpoint].values.flatten 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/settings/README.md: -------------------------------------------------------------------------------- 1 | **This module allows you to quickly and easily build a Settings object for retrieving or updating your Twilio SendGrid Settings.** 2 | 3 | # Quick Start 4 | 5 | Run the [example](../../../../examples/helpers/settings) (make sure you have set your environment variable to include your SENDGRID_API_KEY). 6 | 7 | ```bash 8 | ruby examples/helpers/settings/example.rb 9 | ``` 10 | 11 | ## Usage 12 | 13 | - See the [example](../../../../examples/helpers/settings) for a complete working example. 14 | - [Documentation](https://sendgrid.com/docs/API_Reference/Web_API_v3/Settings/index.html) 15 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/settings/mail_settings_dto.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | class MailSettingsDto 3 | attr_reader :bcc, :address_whitelist, :bounce_purge, :footer, :forward_spam, :forward_bounce, :plain_content, :spam_check, :template 4 | 5 | def self.fetch(sendgrid_client:, name:, query_params:) 6 | sendgrid_client.mail_settings.public_send(name).get(query_params: query_params) 7 | end 8 | 9 | def self.update(sendgrid_client:, name:, request_body:) 10 | sendgrid_client.mail_settings.public_send(name).patch(request_body: request_body) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/settings/partner_settings_dto.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | class PartnerSettingsDto 3 | attr_reader :new_relic 4 | 5 | def self.fetch(sendgrid_client:, name:, query_params:) 6 | sendgrid_client.partner_settings.public_send(name).get(query_params: query_params) 7 | end 8 | 9 | def self.update(sendgrid_client:, name:, request_body:) 10 | sendgrid_client.partner_settings.public_send(name).patch(request_body: request_body) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/settings/settings.rb: -------------------------------------------------------------------------------- 1 | require_relative 'mail_settings_dto' 2 | require_relative 'partner_settings_dto' 3 | require_relative 'tracking_settings_dto' 4 | require_relative 'user_settings_dto' 5 | 6 | module SendGrid 7 | class Settings 8 | attr_accessor :sendgrid_client 9 | 10 | SETTING_TYPES = [SendGrid::MailSettingsDto, SendGrid::TrackingSettingsDto, 11 | SendGrid::PartnerSettingsDto, SendGrid::UserSettingsDto].freeze 12 | 13 | def initialize(sendgrid_client:) 14 | @sendgrid_client = sendgrid_client 15 | end 16 | 17 | SETTING_TYPES.each do |setting_type| 18 | setting_type.instance_methods(false).each do |name| 19 | define_method(name) do |**args| 20 | setting_type.fetch(sendgrid_client: sendgrid_client, name: name, query_params: args) 21 | end 22 | define_method("update_#{name}") do |**args| 23 | setting_type.update(sendgrid_client: sendgrid_client, name: name, request_body: args) 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/settings/tracking_settings_dto.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | class TrackingSettingsDto 3 | attr_reader :open, :click, :google_analytics, :subscription 4 | alias click_tracking click 5 | alias open_tracking open 6 | alias subscription_tracking subscription 7 | 8 | def self.fetch(sendgrid_client:, name:, query_params:) 9 | name = scrub_alias_names(name.to_s) 10 | sendgrid_client.tracking_settings.public_send(name).get(query_params: query_params) 11 | end 12 | 13 | def self.update(sendgrid_client:, name:, request_body:) 14 | name = scrub_alias_names(name.to_s) 15 | sendgrid_client.tracking_settings.public_send(name).patch(request_body: request_body) 16 | end 17 | 18 | def self.scrub_alias_names(name) 19 | name.gsub(/_tracking/, '') 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/settings/user_settings_dto.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | class UserSettingsDto 3 | attr_reader :enforced_tls 4 | 5 | def self.fetch(sendgrid_client:, name:, query_params:) 6 | sendgrid_client.user.settings.public_send(name).get(query_params: query_params) 7 | end 8 | 9 | def self.update(sendgrid_client:, name:, request_body:) 10 | sendgrid_client.user.settings.public_send(name).patch(request_body: request_body) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/stats/email_stats.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module SendGrid 4 | class EmailStats 5 | def initialize(args) 6 | @sendgrid_client = args[:sendgrid_client] 7 | end 8 | 9 | def by_day(start_date, end_date, categories = nil, subusers = nil) 10 | get('day', start_date, end_date, categories, subusers) 11 | end 12 | 13 | def by_week(start_date, end_date, categories = nil, subusers = nil) 14 | get('week', start_date, end_date, categories, subusers) 15 | end 16 | 17 | def by_month(start_date, end_date, categories = nil, subusers = nil) 18 | get('month', start_date, end_date, categories, subusers) 19 | end 20 | 21 | def get(aggregated_by, start_date, end_date, categories = nil, subusers = nil) 22 | params = query_params(aggregated_by, start_date, end_date, categories, subusers) 23 | 24 | response_body = @sendgrid_client.stats.get(query_params: params).body 25 | build_response(response_body) 26 | end 27 | 28 | private 29 | 30 | def query_params(aggregated_by, start_date, end_date, categories, subusers) 31 | params = { 32 | aggregated_by: aggregated_by, 33 | start_date: start_date, 34 | end_date: end_date 35 | } 36 | params.merge(categories: categories) if categories 37 | params.merge(subusers: subusers) if subusers 38 | params 39 | end 40 | 41 | def build_response(response_body) 42 | response_json = JSON.parse(response_body) 43 | StatsResponse.new(response_json) 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/stats/metrics.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | class Metrics 3 | attr_reader :blocks, :bounce_drops, 4 | :bounces, :clicks, :deferred, :delivered, 5 | :invalid_emails, :opens, :processed, :requests, 6 | :spam_report_drops, :spam_reports, :unique_clicks, 7 | :unique_opens, :unsubscribe_drops, :unsubscribes 8 | 9 | def initialize(args = {}) 10 | @date = args['date'] 11 | @blocks = args['blocks'] 12 | @bounce_drops = args['bounce_drops'] 13 | @bounces = args['bounces'] 14 | @clicks = args['clicks'] 15 | @deferred = args['deferred'] 16 | @delivered = args['delivered'] 17 | @invalid_emails = args['invalid_emails'] 18 | @opens = args['opens'] 19 | @processed = args['processed'] 20 | @requests = args['requests'] 21 | @spam_report_drops = args['spam_report_drops'] 22 | @spam_reports = args['spam_reports'] 23 | @unique_clicks = args['unique_clicks'] 24 | @unique_opens = args['unique_opens'] 25 | @unsubscribe_drops = args['unsubscribe_drops'] 26 | @unsubscribes = args['unsubscribes'] 27 | end 28 | 29 | def date 30 | Date.parse(@date) 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/sendgrid/helpers/stats/stats_response.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | class StatsResponse 3 | def initialize(args) 4 | @errors = args['errors'] if args.is_a? Hash 5 | @stats = args if args.is_a? Array 6 | end 7 | 8 | def errors 9 | @errors.map do |error| 10 | error['message'] 11 | end 12 | end 13 | 14 | def error? 15 | !@errors.nil? 16 | end 17 | 18 | def metrics 19 | @stats.flat_map do |stat| 20 | starting_date = stat['date'] 21 | all_stats_for_date = stat['stats'] 22 | 23 | all_stats_for_date.map do |metric| 24 | Metrics.new(metric['metrics'].merge('date' => starting_date)) 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/sendgrid/sendgrid.rb: -------------------------------------------------------------------------------- 1 | # Quickly and easily access the Twilio SendGrid API. 2 | module SendGrid 3 | class API < BaseInterface 4 | # * *Args* : 5 | # - +api_key+ -> your Twilio SendGrid API key 6 | # - +host+ -> the base URL for the API 7 | # - +request_headers+ -> any headers that you want to be globally applied 8 | # - +version+ -> the version of the API you wish to access, 9 | # currently only "v3" is supported 10 | # - +impersonate_subuser+ -> the subuser to impersonate, will be passed 11 | # in the "On-Behalf-Of" header 12 | # - +http_options+ -> http options that you want to be globally applied to each request 13 | # 14 | def initialize(api_key:, host: nil, request_headers: nil, version: nil, impersonate_subuser: nil, http_options: {}) 15 | auth = "Bearer #{api_key}" 16 | host ||= 'https://api.sendgrid.com' 17 | 18 | super(auth: auth, host: host, request_headers: request_headers, version: version, impersonate_subuser: impersonate_subuser, http_options: http_options) 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/sendgrid/twilio_email.rb: -------------------------------------------------------------------------------- 1 | # Quickly and easily access the Twilio Email API. 2 | module TwilioEmail 3 | class API < BaseInterface 4 | # * *Args* : 5 | # - +username+ -> your Twilio Email API key SID or Account SID 6 | # - +password+ -> your Twilio Email API key secret or Account Auth Token 7 | # - +host+ -> the base URL for the API 8 | # - +request_headers+ -> any headers that you want to be globally applied 9 | # - +version+ -> the version of the API you wish to access, 10 | # currently only "v3" is supported 11 | # - +impersonate_subuser+ -> the subuser to impersonate, will be passed 12 | # in the "On-Behalf-Of" header 13 | # 14 | def initialize(username:, password:, host: nil, request_headers: nil, version: nil, impersonate_subuser: nil) 15 | auth = "Basic #{Base64.strict_encode64("#{username}:#{password}")}" 16 | host ||= 'https://email.twilio.com' 17 | 18 | super(auth: auth, host: host, request_headers: request_headers, version: version, impersonate_subuser: impersonate_subuser) 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/sendgrid/version.rb: -------------------------------------------------------------------------------- 1 | module SendGrid 2 | VERSION = '6.7.0'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /sendgrid-ruby.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path('lib', __dir__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require 'sendgrid/version' 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = 'sendgrid-ruby' 7 | spec.version = SendGrid::VERSION 8 | spec.authors = ['Elmer Thomas', 'Robin Johnson', 'Eddie Zaneski'] 9 | spec.email = 'help@twilio.com' 10 | spec.summary = 'Official Twilio SendGrid Gem' 11 | spec.description = 'Official Twilio SendGrid Gem to Interact with Twilio SendGrids API in native Ruby' 12 | spec.homepage = 'http://github.com/sendgrid/sendgrid-ruby' 13 | 14 | spec.required_ruby_version = '>= 2.2' 15 | 16 | spec.license = 'MIT' 17 | spec.files = `git ls-files -z`.split("\x0") 18 | spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) } 19 | spec.test_files = spec.files.grep(/^(test|spec|features)/) 20 | spec.require_paths = ['lib'] 21 | spec.add_dependency 'ruby_http_client', '~> 3.4' 22 | spec.add_development_dependency 'faker' 23 | spec.add_development_dependency 'minitest', '~> 5.9' 24 | spec.add_development_dependency 'pry' 25 | spec.add_development_dependency 'rack' 26 | spec.add_development_dependency 'rake', '~> 13.0' 27 | spec.add_development_dependency 'rspec' 28 | spec.add_development_dependency 'simplecov', '~> 0.18.5' 29 | spec.add_development_dependency 'sinatra', '>= 1.4.7', '< 3' 30 | end 31 | -------------------------------------------------------------------------------- /spec/fixtures/event_webhook.rb: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | module Fixtures 4 | module EventWebhook 5 | PUBLIC_KEY = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g=='.freeze 6 | FAILING_PUBLIC_KEY = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqTxd43gyp8IOEto2LdIfjRQrIbsd4SXZkLW6jDutdhXSJCWHw8REntlo7aNDthvj+y7GjUuFDb/R1NGe1OPzpA=='.freeze 7 | SIGNATURE = 'MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM='.freeze 8 | FAILING_SIGNATURE = 'MEUCIQCtIHJeH93Y+qpYeWrySphQgpNGNr/U+UyUlBkU6n7RAwIgJTz2C+8a8xonZGi6BpSzoQsbVRamr2nlxFDWYNH3j/0='.freeze 9 | TIMESTAMP = '1600112502'.freeze 10 | PAYLOAD = "#{[ 11 | { 12 | email: 'hello@world.com', 13 | event: 'dropped', 14 | reason: 'Bounced Address', 15 | sg_event_id: 'ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA', 16 | sg_message_id: 'LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0', 17 | 'smtp-id': '', 18 | timestamp: 1_600_112_492 19 | } 20 | ].to_json}\r\n".freeze # Be sure to include the trailing carriage return and newline! 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/rack/sendgrid_webhook_verification_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'rack/mock' 3 | require './spec/fixtures/event_webhook' 4 | 5 | unless RUBY_PLATFORM == 'java' 6 | describe Rack::SendGridWebhookVerification do 7 | let(:public_key) { Fixtures::EventWebhook::PUBLIC_KEY } 8 | before do 9 | @app = ->(_env) { [200, { 'Content-Type' => 'text/plain' }, ['Hello']] } 10 | end 11 | 12 | describe 'new' do 13 | it 'should initialize with an app, public key and a path' do 14 | expect do 15 | Rack::SendGridWebhookVerification.new(@app, 'ABC', %r{/email}) 16 | end.not_to raise_error 17 | end 18 | 19 | it 'should initialize with an app, public key and paths' do 20 | expect do 21 | Rack::SendGridWebhookVerification.new(@app, 'ABC', %r{/email}, %r{/event}) 22 | end.not_to raise_error 23 | end 24 | end 25 | 26 | describe 'calling against one path' do 27 | let(:middleware) { Rack::SendGridWebhookVerification.new(@app, public_key, %r{/email}) } 28 | 29 | it "should not intercept when the path doesn't match" do 30 | expect(SendGrid::EventWebhook).to_not receive(:new) 31 | request = Rack::MockRequest.env_for('/login') 32 | status, headers, body = middleware.call(request) 33 | expect(status).to eq(200) 34 | end 35 | 36 | it 'should allow a request through if it is verified' do 37 | options = { 38 | :input => Fixtures::EventWebhook::PAYLOAD, 39 | 'Content-Type' => "application/json" 40 | } 41 | options[SendGrid::EventWebhookHeader::SIGNATURE] = Fixtures::EventWebhook::SIGNATURE 42 | options[SendGrid::EventWebhookHeader::TIMESTAMP] = Fixtures::EventWebhook::TIMESTAMP 43 | request = Rack::MockRequest.env_for('/email', options) 44 | status, headers, body = middleware.call(request) 45 | expect(status).to eq(200) 46 | end 47 | 48 | it 'should short circuit a request to 403 if there is no signature or timestamp' do 49 | options = { 50 | :input => Fixtures::EventWebhook::PAYLOAD, 51 | 'Content-Type' => "application/json" 52 | } 53 | request = Rack::MockRequest.env_for('/email', options) 54 | status, headers, body = middleware.call(request) 55 | expect(status).to eq(403) 56 | end 57 | 58 | it 'should short circuit a request to 403 if the signature is incorrect' do 59 | options = { 60 | :input => Fixtures::EventWebhook::PAYLOAD, 61 | 'Content-Type' => "application/json" 62 | } 63 | options[SendGrid::EventWebhookHeader::SIGNATURE] = Fixtures::EventWebhook::FAILING_SIGNATURE 64 | options[SendGrid::EventWebhookHeader::TIMESTAMP] = Fixtures::EventWebhook::TIMESTAMP 65 | request = Rack::MockRequest.env_for('/email', options) 66 | status, headers, body = middleware.call(request) 67 | expect(status).to eq(403) 68 | end 69 | 70 | it 'should short circuit a request to 403 if the payload is incorrect' do 71 | options = { 72 | :input => 'payload', 73 | 'Content-Type' => "application/json" 74 | } 75 | options[SendGrid::EventWebhookHeader::SIGNATURE] = Fixtures::EventWebhook::SIGNATURE 76 | options[SendGrid::EventWebhookHeader::TIMESTAMP] = Fixtures::EventWebhook::TIMESTAMP 77 | request = Rack::MockRequest.env_for('/email', options) 78 | status, headers, body = middleware.call(request) 79 | expect(status).to eq(403) 80 | end 81 | end 82 | 83 | describe 'calling with multiple paths' do 84 | let(:middleware) { Rack::SendGridWebhookVerification.new(@app, public_key, %r{/email}, %r{/events}) } 85 | 86 | it "should not intercept when the path doesn't match" do 87 | expect(SendGrid::EventWebhook).to_not receive(:new) 88 | request = Rack::MockRequest.env_for('/sms_events') 89 | status, headers, body = middleware.call(request) 90 | expect(status).to eq(200) 91 | end 92 | 93 | it 'should allow a request through if it is verified' do 94 | options = { 95 | :input => Fixtures::EventWebhook::PAYLOAD, 96 | 'Content-Type' => "application/json" 97 | } 98 | options[SendGrid::EventWebhookHeader::SIGNATURE] = Fixtures::EventWebhook::SIGNATURE 99 | options[SendGrid::EventWebhookHeader::TIMESTAMP] = Fixtures::EventWebhook::TIMESTAMP 100 | request = Rack::MockRequest.env_for('/events', options) 101 | status, headers, body = middleware.call(request) 102 | expect(status).to eq(200) 103 | end 104 | 105 | it 'should short circuit a request to 403 if there is no signature or timestamp' do 106 | options = { 107 | :input => Fixtures::EventWebhook::PAYLOAD, 108 | 'Content-Type' => "application/json" 109 | } 110 | request = Rack::MockRequest.env_for('/events', options) 111 | status, headers, body = middleware.call(request) 112 | expect(status).to eq(403) 113 | end 114 | end 115 | 116 | describe 'request body which passed to an app' do 117 | before do 118 | @payload = nil 119 | @spy_app = lambda do |env| 120 | @payload = Rack::Request.new(env).body 121 | [200, { 'Content-Type' => 'text/plain' }, ['Hello']] 122 | end 123 | end 124 | 125 | let(:middleware) { Rack::SendGridWebhookVerification.new(@spy_app, public_key, %r{/email}) } 126 | 127 | it 'keeps orignal reading position' do 128 | options = { 129 | :input => Fixtures::EventWebhook::PAYLOAD, 130 | 'Content-Type' => "application/json" 131 | } 132 | options[SendGrid::EventWebhookHeader::SIGNATURE] = Fixtures::EventWebhook::SIGNATURE 133 | options[SendGrid::EventWebhookHeader::TIMESTAMP] = Fixtures::EventWebhook::TIMESTAMP 134 | request = Rack::MockRequest.env_for('/email', options) 135 | status, headers, body = middleware.call(request) 136 | expect(status).to eq(200) 137 | expect(@payload).not_to be_nil 138 | expect(@payload.pos).to be_zero 139 | end 140 | end 141 | end 142 | end 143 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/eventwebhook/eventwebhook_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require './spec/fixtures/event_webhook' 3 | 4 | describe SendGrid::EventWebhook do 5 | describe '.verify_signature' do 6 | it 'verifies a valid signature' do 7 | unless skip_jruby 8 | expect(verify( 9 | Fixtures::EventWebhook::PUBLIC_KEY, 10 | Fixtures::EventWebhook::PAYLOAD, 11 | Fixtures::EventWebhook::SIGNATURE, 12 | Fixtures::EventWebhook::TIMESTAMP 13 | )).to be true 14 | end 15 | end 16 | 17 | it 'rejects a bad key' do 18 | unless skip_jruby 19 | expect(verify( 20 | Fixtures::EventWebhook::FAILING_PUBLIC_KEY, 21 | Fixtures::EventWebhook::PAYLOAD, 22 | Fixtures::EventWebhook::SIGNATURE, 23 | Fixtures::EventWebhook::TIMESTAMP 24 | )).to be false 25 | end 26 | end 27 | 28 | it 'rejects a bad payload' do 29 | unless skip_jruby 30 | expect(verify( 31 | Fixtures::EventWebhook::PUBLIC_KEY, 32 | 'payload', 33 | Fixtures::EventWebhook::SIGNATURE, 34 | Fixtures::EventWebhook::TIMESTAMP 35 | )).to be false 36 | end 37 | end 38 | 39 | it 'rejects a bad signature' do 40 | unless skip_jruby 41 | expect(verify( 42 | Fixtures::EventWebhook::PUBLIC_KEY, 43 | Fixtures::EventWebhook::PAYLOAD, 44 | Fixtures::EventWebhook::FAILING_SIGNATURE, 45 | Fixtures::EventWebhook::TIMESTAMP 46 | )).to be false 47 | end 48 | end 49 | 50 | it 'rejects a bad timestamp' do 51 | unless skip_jruby 52 | expect(verify( 53 | Fixtures::EventWebhook::PUBLIC_KEY, 54 | Fixtures::EventWebhook::PAYLOAD, 55 | Fixtures::EventWebhook::SIGNATURE, 56 | 'timestamp' 57 | )).to be false 58 | end 59 | end 60 | 61 | it 'rejects a missing signature' do 62 | unless skip_jruby 63 | expect(verify( 64 | Fixtures::EventWebhook::PUBLIC_KEY, 65 | Fixtures::EventWebhook::PAYLOAD, 66 | nil, 67 | Fixtures::EventWebhook::TIMESTAMP 68 | )).to be false 69 | end 70 | end 71 | 72 | it 'throws an error when using jruby' do 73 | if skip_jruby 74 | expect do 75 | verify( 76 | Fixtures::EventWebhook::PUBLIC_KEY, 77 | Fixtures::EventWebhook::PAYLOAD, 78 | Fixtures::EventWebhook::SIGNATURE, 79 | Fixtures::EventWebhook::TIMESTAMP 80 | ) 81 | end.to raise_error(SendGrid::EventWebhook::NotSupportedError) 82 | end 83 | end 84 | end 85 | end 86 | 87 | describe SendGrid::EventWebhookHeader do 88 | it 'sets the signature header constant' do 89 | expect(SendGrid::EventWebhookHeader::SIGNATURE).to eq("HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_SIGNATURE") 90 | end 91 | 92 | it 'sets the timestamp header constant' do 93 | expect(SendGrid::EventWebhookHeader::TIMESTAMP).to eq("HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_TIMESTAMP") 94 | end 95 | end 96 | 97 | def verify(public_key, payload, signature, timestamp) 98 | ew = SendGrid::EventWebhook.new 99 | ec_public_key = ew.convert_public_key_to_ecdsa(public_key) 100 | ew.verify_signature(ec_public_key, payload, signature, timestamp) 101 | end 102 | 103 | def skip_jruby 104 | RUBY_PLATFORM == 'java' 105 | end 106 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/ip_management/ip_management_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::IpManagement do 4 | let(:sendgrid_client) { SendGrid::API.new(api_key: 'fake_key').client } 5 | let(:ip_management) { SendGrid::IpManagement.new(sendgrid_client: sendgrid_client) } 6 | 7 | describe '.new' do 8 | it 'initializes correctly' do 9 | expect(ip_management).to be_a SendGrid::IpManagement 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/settings/mail_settings_dto_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::MailSettingsDto do 4 | let(:sendgrid_client) { SendGrid::API.new(api_key: 'fake_key').client } 5 | let(:mail_settings) { SendGrid::MailSettingsDto } 6 | let(:setting_name) { 'bcc' } 7 | let(:setting_params) { { email: Faker::Internet.email, enabled: rand(1..100).even? } } 8 | 9 | it { should respond_to :bcc } 10 | it { should respond_to :address_whitelist } 11 | it { should respond_to :bounce_purge } 12 | it { should respond_to :footer } 13 | it { should respond_to :forward_spam } 14 | it { should respond_to :forward_bounce } 15 | it { should respond_to :plain_content } 16 | it { should respond_to :spam_check } 17 | it { should respond_to :template } 18 | 19 | describe '.fetch' do 20 | it 'calls get on sendgrid_client' do 21 | args = { sendgrid_client: sendgrid_client, name: setting_name, query_params: {} } 22 | expect(mail_settings.fetch(**args)).to be_a SendGrid::Response 23 | end 24 | end 25 | 26 | describe '.update' do 27 | it 'calls patch on sendgrid_client' do 28 | args = { sendgrid_client: sendgrid_client, name: setting_name, request_body: setting_params } 29 | expect(mail_settings.update(**args)).to be_a SendGrid::Response 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/settings/partner_settings_dto_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::PartnerSettingsDto do 4 | let(:sendgrid_client) { SendGrid::API.new(api_key: 'fake_key').client } 5 | let(:partner_settings) { SendGrid::PartnerSettingsDto } 6 | let(:setting_name) { 'new_relic' } 7 | let(:setting_params) { { license_key: 'key', enabled: rand(1..100).even? } } 8 | 9 | it { should respond_to :new_relic } 10 | 11 | describe '.fetch' do 12 | it 'calls get on sendgrid_client' do 13 | args = { sendgrid_client: sendgrid_client, name: setting_name, query_params: {} } 14 | expect(partner_settings.fetch(**args)).to be_a SendGrid::Response 15 | end 16 | end 17 | 18 | describe '.update' do 19 | it 'calls patch on sendgrid_client' do 20 | args = { sendgrid_client: sendgrid_client, name: setting_name, request_body: setting_params } 21 | expect(partner_settings.update(**args)).to be_a SendGrid::Response 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/settings/settings_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::Settings do 4 | let(:sendgrid_client) { SendGrid::API.new(api_key: 'fake_key').client } 5 | let(:settings) { SendGrid::Settings.new(sendgrid_client: sendgrid_client) } 6 | 7 | describe '.new' do 8 | it 'initializes correctly' do 9 | expect(settings).to be_a SendGrid::Settings 10 | end 11 | end 12 | 13 | describe '.bcc' do 14 | it 'fetches bcc data' do 15 | expect(settings.bcc).to be_a SendGrid::Response 16 | end 17 | end 18 | 19 | describe '.update_bcc' do 20 | it 'updates bcc' do 21 | bcc_response = settings.update_bcc(enabled: true, email: 'email@example.com') 22 | expect(bcc_response).to be_a SendGrid::Response 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/settings/tracking_settings_dto_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::TrackingSettingsDto do 4 | let(:sendgrid_client) { SendGrid::API.new(api_key: 'fake_key').client } 5 | let(:tracking_settings) { SendGrid::TrackingSettingsDto } 6 | let(:setting_name) { 'open_tracking' } 7 | let(:setting_params) { { enabled: rand(1..100).even? } } 8 | 9 | it { should respond_to :open_tracking } 10 | it { should respond_to :click_tracking } 11 | it { should respond_to :google_analytics } 12 | it { should respond_to :subscription_tracking } 13 | 14 | describe '.fetch' do 15 | it 'calls get on sendgrid_client' do 16 | args = { sendgrid_client: sendgrid_client, name: setting_name, query_params: {} } 17 | expect(tracking_settings.fetch(**args)).to be_a SendGrid::Response 18 | end 19 | end 20 | 21 | describe '.update' do 22 | it 'calls patch on sendgrid_client' do 23 | args = { sendgrid_client: sendgrid_client, name: setting_name, request_body: setting_params } 24 | expect(tracking_settings.update(**args)).to be_a SendGrid::Response 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/settings/user_settings_dto_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::UserSettingsDto do 4 | let(:sendgrid_client) { SendGrid::API.new(api_key: 'fake_key').client } 5 | let(:user_settings) { SendGrid::UserSettingsDto } 6 | let(:setting_name) { 'enforced_tls' } 7 | let(:setting_params) { { require_tls: rand(1..100).even? } } 8 | 9 | it { should respond_to :enforced_tls } 10 | 11 | describe '.fetch' do 12 | it 'calls get on sendgrid_client' do 13 | args = { sendgrid_client: sendgrid_client, name: setting_name, query_params: {} } 14 | expect(user_settings.fetch(**args)).to be_a SendGrid::Response 15 | end 16 | end 17 | 18 | describe '.update' do 19 | it 'calls patch on sendgrid_client' do 20 | args = { sendgrid_client: sendgrid_client, name: setting_name, request_body: setting_params } 21 | expect(user_settings.update(**args)).to be_a SendGrid::Response 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/stats/email_stats_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::EmailStats do 4 | let(:sg_client) { SendGrid::API.new(api_key: 'abcd').client } 5 | let(:stats) { SendGrid::EmailStats.new(sendgrid_client: sg_client) } 6 | let(:sg_response) { double('SendGrid::Response') } 7 | 8 | let(:sample_response) do 9 | [{ 10 | 'date' => '2017-10-01', 11 | 'stats' => [ 12 | { 'metrics' => 13 | { 14 | 'blocks' => 101, 15 | 'bounce_drops' => 102, 16 | 'bounces' => 103, 17 | 'clicks' => 104, 18 | 'deferred' => 105, 19 | 'delivered' => 106, 20 | 'invalid_emails' => 107, 21 | 'opens' => 108, 22 | 'processed' => 109, 23 | 'requests' => 110, 24 | 'spam_report_drops' => 111, 25 | 'spam_reports' => 112, 26 | 'unique_clicks' => 113, 27 | 'unique_opens' => 114, 28 | 'unsubscribe_drops' => 115, 29 | 'unsubscribes' => 116 30 | } } 31 | ] 32 | }] 33 | end 34 | 35 | let(:error_response) do 36 | { 37 | 'errors' => [ 38 | { 39 | 'message' => 'end_date should be a YYYY-MM-DD formatted date' 40 | } 41 | ] 42 | } 43 | end 44 | 45 | describe '.new' do 46 | it 'initializes with SendGrid::Client' do 47 | expect(stats).to be_a SendGrid::EmailStats 48 | end 49 | end 50 | 51 | describe 'successful response' do 52 | before do 53 | allow_any_instance_of(SendGrid::Response).to receive(:body) { sample_response.to_json } 54 | end 55 | 56 | describe '#by_day' do 57 | it 'fetches data aggregated by day' do 58 | day_stats = stats.by_day('2017-10-01', '2017-10-02') 59 | day_metrics = day_stats.metrics.first 60 | 61 | expect(day_metrics).to be_a SendGrid::Metrics 62 | expect(day_metrics.date.to_s).to eq('2017-10-01') 63 | expect(day_metrics.requests).to eq(110) 64 | expect(day_metrics.clicks).to eq(104) 65 | expect(day_metrics.bounces).to eq(103) 66 | expect(day_metrics.opens).to eq(108) 67 | end 68 | end 69 | 70 | describe '#by_week' do 71 | it 'fetches data aggregated by week' do 72 | day_stats = stats.by_week('2017-10-01', '2017-10-12') 73 | day_metrics = day_stats.metrics.first 74 | 75 | expect(day_metrics).to be_a SendGrid::Metrics 76 | expect(day_metrics.date.to_s).to eq('2017-10-01') 77 | expect(day_metrics.requests).to eq(110) 78 | expect(day_metrics.clicks).to eq(104) 79 | expect(day_metrics.bounces).to eq(103) 80 | expect(day_metrics.opens).to eq(108) 81 | end 82 | end 83 | 84 | describe '#by_month' do 85 | it 'fetches data aggregated by month' do 86 | day_stats = stats.by_month('2017-10-01', '2017-11-01') 87 | day_metrics = day_stats.metrics.first 88 | 89 | expect(day_metrics).to be_a SendGrid::Metrics 90 | expect(day_metrics.date.to_s).to eq('2017-10-01') 91 | expect(day_metrics.requests).to eq(110) 92 | expect(day_metrics.clicks).to eq(104) 93 | expect(day_metrics.bounces).to eq(103) 94 | expect(day_metrics.opens).to eq(108) 95 | end 96 | end 97 | end 98 | 99 | describe 'error response' do 100 | before do 101 | allow_any_instance_of(SendGrid::Response).to receive(:body) { error_response.to_json } 102 | end 103 | 104 | it 'fetches data aggregated by month' do 105 | day_stats = stats.by_month('2017-10-01', '2017-10-02') 106 | 107 | expect(day_stats.errors).to include('end_date should be a YYYY-MM-DD formatted date') 108 | expect(day_stats.error?).to be_truthy 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/stats/metrics_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::Metrics do 4 | let(:params) do 5 | { 6 | 'date' => '2017-10-01', 7 | 'blocks' => 101, 8 | 'bounce_drops' => 102, 9 | 'bounces' => 103, 10 | 'clicks' => 104, 11 | 'deferred' => 105, 12 | 'delivered' => 106, 13 | 'invalid_emails' => 107, 14 | 'opens' => 108, 15 | 'processed' => 109, 16 | 'requests' => 110, 17 | 'spam_report_drops' => 111, 18 | 'spam_reports' => 112, 19 | 'unique_clicks' => 113, 20 | 'unique_opens' => 114, 21 | 'unsubscribe_drops' => 115, 22 | 'unsubscribes' => 116 23 | } 24 | end 25 | 26 | subject { described_class.new(params) } 27 | 28 | it 'initializes with metric parameters' do 29 | expect(subject).to be_a SendGrid::Metrics 30 | end 31 | 32 | it 'returns date as object' do 33 | expect(subject.date).to be_a Date 34 | end 35 | 36 | %w[ 37 | blocks bounce_drops bounces clicks deferred delivered invalid_emails 38 | opens processed requests spam_report_drops spam_reports unique_clicks 39 | unique_opens unsubscribe_drops unsubscribes 40 | ].each do |attribute| 41 | it "responds to #{attribute}" do 42 | expect(subject).to respond_to(attribute.to_sym) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/sendgrid/helpers/stats/stats_response_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::StatsResponse do 4 | let(:params) do 5 | [{ 6 | 'date' => '2017-10-01', 7 | 'stats' => [ 8 | { 'metrics' => 9 | { 10 | 'blocks' => 101, 11 | 'bounce_drops' => 102, 12 | 'bounces' => 103, 13 | 'clicks' => 104, 14 | 'deferred' => 105, 15 | 'delivered' => 106, 16 | 'invalid_emails' => 107, 17 | 'opens' => 108, 18 | 'processed' => 109, 19 | 'requests' => 110, 20 | 'spam_report_drops' => 111, 21 | 'spam_reports' => 112, 22 | 'unique_clicks' => 113, 23 | 'unique_opens' => 114, 24 | 'unsubscribe_drops' => 115, 25 | 'unsubscribes' => 116 26 | } } 27 | ] 28 | }] 29 | end 30 | 31 | subject { described_class.new(params) } 32 | 33 | it 'initialized with JSON response body' do 34 | expect(subject).to be_a SendGrid::StatsResponse 35 | end 36 | 37 | describe '#metrics' do 38 | it 'returns an array of metrics' do 39 | metric = subject.metrics.first 40 | 41 | expect(subject.metrics).to be_a Array 42 | expect(metric.date.to_s).to eq('2017-10-01') 43 | expect(metric.requests).to eq(110) 44 | expect(metric.clicks).to eq(104) 45 | expect(metric.bounces).to eq(103) 46 | expect(metric.opens).to eq(108) 47 | end 48 | end 49 | 50 | context 'errors' do 51 | let(:error_params) do 52 | { 53 | 'errors' => [ 54 | { 55 | 'message' => 'end_date should be a YYYY-MM-DD formatted date' 56 | } 57 | ] 58 | } 59 | end 60 | 61 | subject { described_class.new(error_params) } 62 | 63 | describe '#errors' do 64 | it 'shows a list of errors' do 65 | expect(subject.errors).to include('end_date should be a YYYY-MM-DD formatted date') 66 | end 67 | end 68 | 69 | describe '#error?' do 70 | it 'returns true if there is an error' do 71 | expect(subject.error?).to be_truthy 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/sendgrid/sendgrid_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SendGrid::API do 4 | describe '.new' do 5 | it 'initializes correctly' do 6 | mail_client = SendGrid::API.new(api_key: 'fake_key') 7 | expect(mail_client.request_headers['Authorization']).to eq('Bearer fake_key') 8 | expect(mail_client.host).to eq('https://api.sendgrid.com') 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/sendgrid/twilio_email_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe TwilioEmail::API do 4 | describe '.new' do 5 | it 'initializes correctly' do 6 | mail_client = TwilioEmail::API.new(username: 'username', password: 'password') 7 | expect(mail_client.request_headers['Authorization']).to eq('Basic dXNlcm5hbWU6cGFzc3dvcmQ=') 8 | expect(mail_client.host).to eq('https://email.twilio.com') 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'simplecov' 2 | SimpleCov.start 3 | require 'rubygems' 4 | require 'bundler/setup' 5 | require 'pry' 6 | require 'faker' 7 | 8 | RSpec.configure do |config| 9 | Dir["#{File.dirname(__FILE__)}/../lib/sendgrid-ruby.rb"].sort.each { |ext| require ext } 10 | 11 | config.color = true 12 | end 13 | -------------------------------------------------------------------------------- /static/img/github-fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/sendgrid-ruby/02b6a2a46dbf38c53a6dd8469f5da69a55c78a47/static/img/github-fork.png -------------------------------------------------------------------------------- /static/img/github-sign-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/sendgrid-ruby/02b6a2a46dbf38c53a6dd8469f5da69a55c78a47/static/img/github-sign-up.png -------------------------------------------------------------------------------- /test/sendgrid/helpers/mail/test_attachment.rb: -------------------------------------------------------------------------------- 1 | require_relative "../../../../lib/sendgrid/helpers/mail/attachment" 2 | include SendGrid 3 | require "json" 4 | require "minitest/autorun" 5 | 6 | class TestAttachment < Minitest::Test 7 | SAMPLE_INPUT = "Es blüht so grün wie Blüten blüh'n im Frühling 8 | Es blüht so grün wie Blüten blüh'n im Frühling 9 | Es blüht so grün wie Blüten blüh'n im Frühling 10 | Es blüht so grün wie Blüten blüh'n im Frühling 11 | Es blüht so grün wie Blüten blüh'n im Frühling 12 | ".force_encoding('UTF-8').encode 13 | 14 | def setup; end 15 | 16 | def test_io_enocding 17 | attachment = Attachment.new 18 | attachment.content = StringIO.new(SAMPLE_INPUT) 19 | 20 | expected = { 21 | "content" => "RXMgYmzDvGh0IHNvIGdyw7xuIHdpZSBCbMO8dGVuIGJsw7xoJ24gaW0gRnLD\nvGhsaW5nCkVzIGJsw7xodCBzbyBncsO8biB3aWUgQmzDvHRlbiBibMO8aCdu\nIGltIEZyw7xobGluZwpFcyBibMO8aHQgc28gZ3LDvG4gd2llIEJsw7x0ZW4g\nYmzDvGgnbiBpbSBGcsO8aGxpbmcKRXMgYmzDvGh0IHNvIGdyw7xuIHdpZSBC\nbMO8dGVuIGJsw7xoJ24gaW0gRnLDvGhsaW5nCkVzIGJsw7xodCBzbyBncsO8\nbiB3aWUgQmzDvHRlbiBibMO8aCduIGltIEZyw7xobGluZwo=\n" 22 | } 23 | 24 | json = attachment.to_json 25 | 26 | # Double check that the decoded json matches original input. 27 | decoded = Base64.decode64(json["content"]).force_encoding('UTF-8').encode 28 | 29 | assert_equal(decoded, SAMPLE_INPUT) 30 | 31 | assert_equal(json, expected) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/sendgrid/helpers/mail/test_category.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../../lib/sendgrid/helpers/mail/mail' 2 | require 'minitest/autorun' 3 | 4 | class TestCategory < Minitest::Test 5 | include SendGrid 6 | 7 | def setup 8 | @category = Category.new(name: 'foo') 9 | end 10 | 11 | def test_aliases 12 | assert_equal @category.method(:name), @category.method(:category) 13 | end 14 | 15 | def test_name 16 | assert_equal @category.name, 'foo' 17 | end 18 | 19 | def test_to_json 20 | expected_json = { 21 | 'category' => 'foo' 22 | } 23 | assert_equal @category.to_json, expected_json 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/sendgrid/helpers/mail/test_data_residency.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../../lib/sendgrid-ruby' 2 | require 'minitest/autorun' 3 | 4 | class TestDataResidency < Minitest::Test 5 | include SendGrid 6 | 7 | def setup 8 | @global_email = 'https://api.sendgrid.com' 9 | @eu_email = 'https://api.eu.sendgrid.com' 10 | end 11 | 12 | def test_with_global_data_residency 13 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 14 | sg.sendgrid_data_residency(region: 'global') 15 | assert_equal @global_email, sg.host 16 | end 17 | 18 | def test_with_global_eu_residency 19 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 20 | sg.sendgrid_data_residency(region: 'eu') 21 | assert_equal @eu_email, sg.host 22 | end 23 | 24 | def test_with_global_nil_residency 25 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 26 | assert_raises(ArgumentError) do 27 | sg.sendgrid_data_residency(region: nil) 28 | end 29 | end 30 | 31 | def test_with_global_invalid_residency 32 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 33 | assert_raises(ArgumentError) do 34 | sg.sendgrid_data_residency(region: "abc") 35 | end 36 | end 37 | 38 | def test_with_global_empty_residency 39 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 40 | assert_raises(ArgumentError) do 41 | sg.sendgrid_data_residency(region: "") 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /test/sendgrid/helpers/mail/test_email.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../../lib/sendgrid/helpers/mail/email' 2 | require 'minitest/autorun' 3 | 4 | class TestEmail < Minitest::Test 5 | include SendGrid 6 | 7 | def test_split_email_full_email 8 | @email = Email.new(email: 'Example User ') 9 | expected_json = { 10 | 'email' => 'test1@example.com', 11 | 'name' => 'Example User' 12 | } 13 | assert_equal @email.to_json, expected_json 14 | end 15 | 16 | def test_split_email_only_email 17 | @email = Email.new(email: 'test1@example.com') 18 | expected_json = { 19 | 'email' => 'test1@example.com' 20 | } 21 | assert_equal @email.to_json, expected_json 22 | end 23 | 24 | def test_split_email_name_and_email 25 | @email = Email.new(name: 'Example User', email: 'test1@example.com') 26 | expected_json = { 27 | 'email' => 'test1@example.com', 28 | 'name' => 'Example User' 29 | } 30 | assert_equal @email.to_json, expected_json 31 | end 32 | 33 | def test_mandatory_email_missing 34 | assert_raises(ArgumentError) { Email.new(email: nil) } 35 | assert_raises(ArgumentError) { Email.new(email: "") } 36 | end 37 | 38 | def test_invalid_email 39 | assert_raises(ArgumentError) { Email.new(email: "some-invalid-string") } 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /test/sendgrid/helpers/mail/test_personalizations.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../../lib/sendgrid/helpers/mail/personalization' 2 | require 'minitest/autorun' 3 | 4 | class TestPersonalization < Minitest::Test 5 | include SendGrid 6 | 7 | def test_add_to 8 | @personalization = Personalization.new 9 | @personalization.add_to(Email.new(email: 'test1@example.com', name: 'Example User')) 10 | @personalization.add_to(Email.new(email: 'test2@example.com', name: 'Example User 2')) 11 | expected_json = { 12 | 'to' => [ 13 | { 14 | 'email' => 'test1@example.com', 15 | 'name' => 'Example User' 16 | }, 17 | { 18 | 'email' => 'test2@example.com', 19 | 'name' => 'Example User 2' 20 | } 21 | ] 22 | } 23 | assert_equal @personalization.to_json, expected_json 24 | end 25 | 26 | def test_duplicate_add_to 27 | @personalization = Personalization.new 28 | @personalization.add_to(Email.new(email: 'test1@example.com', name: 'Example User')) 29 | @personalization.add_to(Email.new(email: 'TEST2@EXAMPLE.COM', name: 'Example User 2')) 30 | 31 | assert_raises(DuplicatePersonalizationError) do 32 | @personalization.add_to(Email.new(email: 'test1@example.com', name: 'Duplicate User')) 33 | end 34 | 35 | assert_raises(DuplicatePersonalizationError) do 36 | @personalization.add_to(Email.new(email: 'TEST1@EXAMPLE.COM', name: 'Duplicate User')) 37 | end 38 | 39 | assert_raises(DuplicatePersonalizationError) do 40 | @personalization.add_to(Email.new(email: 'test2@example.com', name: 'Duplicate User 2')) 41 | end 42 | 43 | assert_raises(DuplicatePersonalizationError) do 44 | @personalization.add_to(Email.new(email: 'TEST2@EXAMPLE.COM', name: 'Duplicate User 2')) 45 | end 46 | end 47 | 48 | def test_add_from 49 | @personalization = Personalization.new 50 | @personalization.add_from(Email.new(email: 'from1@example.com', name: 'Example Sender')) 51 | expected_json = { 52 | 'from' => { 53 | 'email' => 'from1@example.com', 54 | 'name' => 'Example Sender' 55 | } 56 | } 57 | 58 | assert_equal @personalization.to_json, expected_json 59 | end 60 | 61 | def test_add_cc 62 | @personalization = Personalization.new 63 | @personalization.add_cc(Email.new(email: 'test1@example.com', name: 'Example User')) 64 | @personalization.add_cc(Email.new(email: 'test2@example.com', name: 'Example User 2')) 65 | expected_json = { 66 | 'cc' => [ 67 | { 68 | 'email' => 'test1@example.com', 69 | 'name' => 'Example User' 70 | }, 71 | { 72 | 'email' => 'test2@example.com', 73 | 'name' => 'Example User 2' 74 | } 75 | ] 76 | } 77 | assert_equal @personalization.to_json, expected_json 78 | end 79 | 80 | def test_duplicate_add_cc 81 | @personalization = Personalization.new 82 | @personalization.add_cc(Email.new(email: 'test1@example.com', name: 'Example User')) 83 | @personalization.add_cc(Email.new(email: 'TEST2@EXAMPLE.COM', name: 'Example User 2')) 84 | 85 | assert_raises(DuplicatePersonalizationError) do 86 | @personalization.add_cc(Email.new(email: 'test1@example.com', name: 'Duplicate User')) 87 | end 88 | 89 | assert_raises(DuplicatePersonalizationError) do 90 | @personalization.add_cc(Email.new(email: 'TEST1@EXAMPLE.COM', name: 'Duplicate User')) 91 | end 92 | 93 | assert_raises(DuplicatePersonalizationError) do 94 | @personalization.add_cc(Email.new(email: 'test2@example.com', name: 'Duplicate User 2')) 95 | end 96 | 97 | assert_raises(DuplicatePersonalizationError) do 98 | @personalization.add_cc(Email.new(email: 'TEST2@EXAMPLE.COM', name: 'Duplicate User 2')) 99 | end 100 | end 101 | 102 | def test_add_bcc 103 | @personalization = Personalization.new 104 | @personalization.add_bcc(Email.new(email: 'test1@example.com', name: 'Example User')) 105 | @personalization.add_bcc(Email.new(email: 'test2@example.com', name: 'Example User 2')) 106 | expected_json = { 107 | 'bcc' => [ 108 | { 109 | 'email' => 'test1@example.com', 110 | 'name' => 'Example User' 111 | }, 112 | { 113 | 'email' => 'test2@example.com', 114 | 'name' => 'Example User 2' 115 | } 116 | ] 117 | } 118 | assert_equal @personalization.to_json, expected_json 119 | end 120 | 121 | def test_duplicate_add_bcc 122 | @personalization = Personalization.new 123 | @personalization.add_bcc(Email.new(email: 'test1@example.com', name: 'Example User')) 124 | @personalization.add_bcc(Email.new(email: 'TEST2@EXAMPLE.COM', name: 'Example User 2')) 125 | 126 | assert_raises(DuplicatePersonalizationError) do 127 | @personalization.add_bcc(Email.new(email: 'test1@example.com', name: 'Duplicate User')) 128 | end 129 | 130 | assert_raises(DuplicatePersonalizationError) do 131 | @personalization.add_bcc(Email.new(email: 'TEST1@EXAMPLE.COM', name: 'Duplicate User')) 132 | end 133 | 134 | assert_raises(DuplicatePersonalizationError) do 135 | @personalization.add_bcc(Email.new(email: 'test2@example.com', name: 'Duplicate User 2')) 136 | end 137 | 138 | assert_raises(DuplicatePersonalizationError) do 139 | @personalization.add_bcc(Email.new(email: 'TEST2@EXAMPLE.COM', name: 'Duplicate User 2')) 140 | end 141 | end 142 | 143 | def test_add_header 144 | @personalization = Personalization.new 145 | @personalization.add_header(Header.new(key: 'X-Test', value: 'True')) 146 | expected_json = { 147 | 'headers' => { 148 | 'X-Test' => 'True' 149 | } 150 | } 151 | assert_equal @personalization.to_json, expected_json 152 | @personalization.add_header(Header.new(key: 'X-Test 1', value: 'False')) 153 | expected_json = { 154 | 'headers' => { 155 | 'X-Test' => 'True', 156 | 'X-Test 1' => 'False' 157 | } 158 | } 159 | assert_equal @personalization.to_json, expected_json 160 | end 161 | 162 | def test_add_substitution 163 | @personalization = Personalization.new 164 | @personalization.add_substitution(Substitution.new(key: '%name%', value: 'Example User')) 165 | expected_json = { 166 | 'substitutions' => { 167 | '%name%' => 'Example User' 168 | } 169 | } 170 | assert_equal @personalization.to_json, expected_json 171 | @personalization.add_substitution(Substitution.new(key: '%name 1%', value: 'Example User 1')) 172 | expected_json = { 173 | 'substitutions' => { 174 | '%name%' => 'Example User', 175 | '%name 1%' => 'Example User 1' 176 | } 177 | } 178 | assert_equal @personalization.to_json, expected_json 179 | end 180 | 181 | def test_add_custom_arg 182 | @personalization = Personalization.new 183 | @personalization.add_custom_arg(CustomArg.new(key: 'user_id', value: '343')) 184 | expected_json = { 185 | 'custom_args' => { 186 | 'user_id' => '343' 187 | } 188 | } 189 | assert_equal @personalization.to_json, expected_json 190 | @personalization.add_custom_arg(CustomArg.new(key: 'city', value: 'denver')) 191 | expected_json = { 192 | 'custom_args' => { 193 | 'user_id' => '343', 194 | 'city' => 'denver' 195 | } 196 | } 197 | assert_equal @personalization.to_json, expected_json 198 | end 199 | 200 | def test_add_dynamic_template_data 201 | @personalization = Personalization.new 202 | @personalization.add_dynamic_template_data( 203 | 'name' => 'Example User', 204 | 'city' => 'Denver' 205 | ) 206 | expected_json = { 207 | 'dynamic_template_data' => { 208 | 'name' => 'Example User', 209 | 'city' => 'Denver' 210 | } 211 | } 212 | assert_equal @personalization.to_json, expected_json 213 | end 214 | end 215 | -------------------------------------------------------------------------------- /test/sendgrid/permissions/test_scopes.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../lib/sendgrid/helpers/permissions/scope' 2 | require 'minitest/autorun' 3 | 4 | class TestCategory < Minitest::Test 5 | include SendGrid 6 | 7 | # usecases 8 | # 1. test admin scopes 9 | # 2. test read only scopes 10 | # 3. test read only and full access scopes for a method by hardcoding 11 | # 4. test read only and full access scopes by loading scopes.yaml 12 | 13 | def setup 14 | @scopes_from_yaml = YAML.load_file("#{File.dirname(__FILE__)}/../../../lib/sendgrid/helpers/permissions/scopes.yml").freeze 15 | end 16 | 17 | def test_admin_scopes 18 | assert_equal Scope.admin_permissions, @scopes_from_yaml.values.map(&:values).flatten 19 | end 20 | 21 | def test_read_only_scopes 22 | assert_equal Scope.read_only_permissions, @scopes_from_yaml.map { |_, v| v[:read] }.flatten 23 | end 24 | 25 | def test_read_only_and_full_access_for_mail_hardcoded 26 | assert_equal Scope.mail_read_only_permissions, ["mail.batch.read"] 27 | assert_equal Scope.mail_full_access_permissions, ["mail.send", "mail.batch.create", "mail.batch.delete", "mail.batch.read", "mail.batch.update"] 28 | end 29 | 30 | def test_read_only_and_full_access_from_file 31 | @scopes_from_yaml.each_key do |endpoint| 32 | assert_equal Scope.send("#{endpoint}_read_only_permissions"), @scopes_from_yaml[endpoint][:read] 33 | assert_equal Scope.send("#{endpoint}_full_access_permissions"), @scopes_from_yaml[endpoint].values.flatten 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /twilio_sendgrid_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/sendgrid-ruby/02b6a2a46dbf38c53a6dd8469f5da69a55c78a47/twilio_sendgrid_logo.png -------------------------------------------------------------------------------- /use-cases/README.md: -------------------------------------------------------------------------------- 1 | This directory provides examples for specific use cases. 2 | 3 | Please [open an issue](https://github.com/sendgrid/sendgrid-ruby/issues) or [make a pull request](https://github.com/sendgrid/sendgrid-ruby/pulls) for any use cases you would like us to document here. Thank you! 4 | 5 | # Email Use Cases 6 | * [Transactional Templates](transactional-templates.md) 7 | * [Legacy Templates](legacy-templates.md) 8 | * [Personalizations](personalizations.md) 9 | 10 | # Twilio Use Cases 11 | * [Twilio Setup](twilio-setup.md) 12 | * [Send an Email With Twilio Email (Pilot)](twilio-email.md) 13 | * [Send an SMS Message](sms.md) 14 | 15 | # Non-Email Use Cases 16 | * [How to Set up a Domain Authentication](domain-authentication.md) 17 | * [How to View Email Statistics](email-statistics.md) 18 | -------------------------------------------------------------------------------- /use-cases/domain-authentication.md: -------------------------------------------------------------------------------- 1 | # How to Setup a Domain Authentication 2 | 3 | You can find documentation for how to setup a domain authentication via the UI [here](https://sendgrid.com/docs/ui/account-and-settings/how-to-set-up-domain-authentication/) and via API [here](../USAGE.md#sender-authentication). 4 | 5 | Find more information about all of Twilio SendGrid's authentication related documentation [here](https://sendgrid.com/docs/ui/account-and-settings/). 6 | -------------------------------------------------------------------------------- /use-cases/email-statistics.md: -------------------------------------------------------------------------------- 1 | # How to View Email Statistics 2 | 3 | You can find documentation for how to view your email statistics via the UI [here](https://app.sendgrid.com/statistics) and via API [here](../USAGE.md#stats). 4 | 5 | Alternatively, we can post events to a URL of your choice via our [Event Webhook](https://sendgrid.com/docs/API_Reference/Webhooks/event.html) about events that occur as Twilio SendGrid processes your email. 6 | 7 | You can also use the email statistics helper to make it easier to interact with the API. 8 | 9 | ```ruby 10 | require 'sendgrid-ruby' 11 | require 'date' 12 | 13 | include SendGrid 14 | 15 | sg_client = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']).client 16 | stats = SendGrid::EmailStats.new(sendgrid_client: sg_client) 17 | 18 | # Fetch stats by day, between 2 dates 19 | from = Date.new(2017, 10, 01) 20 | to = Date.new(2017, 10, 12) 21 | 22 | email_stats = stats.by_day(from, to) 23 | 24 | email_stats.metrics 25 | 26 | if !email_stats.error? 27 | email_stats.metrics.each do |metric| 28 | puts "Date - #{metric.date}" 29 | puts "Number of Requests - #{metric.requests}" 30 | puts "Bounces - #{metric.bounces}" 31 | puts "Opens - #{metric.opens}" 32 | puts "Clicks - #{metric.clicks}" 33 | end 34 | end 35 | 36 | # Fetch stats by week, between 2 dates for a category 37 | from = Date.new(2017, 10, 01) 38 | to = Date.new(2017, 10, 12) 39 | category = 'abcd' 40 | 41 | email_stats = stats.by_week(from, to, category) 42 | 43 | if !email_stats.error? 44 | email_stats.metrics.each do |metric| 45 | puts "Date - #{metric.date}" 46 | puts "Number of Requests - #{metric.requests}" 47 | puts "Bounces - #{metric.bounces}" 48 | puts "Opens - #{metric.opens}" 49 | puts "Clicks - #{metric.clicks}" 50 | end 51 | end 52 | ``` 53 | -------------------------------------------------------------------------------- /use-cases/legacy-templates.md: -------------------------------------------------------------------------------- 1 | # Legacy Templates 2 | 3 | For this example, we assume you have created a [legacy transactional template](https://sendgrid.com/docs/User_Guide/Transactional_Templates/index.html) in the UI or via the API. Following is the template content we used for testing. 4 | 5 | Template ID (replace with your own): 6 | ```text 7 | 13b8f94f-bcae-4ec6-b752-70d6cb59f932 8 | ``` 9 | 10 | Email Subject: 11 | ```text 12 | <%subject%> 13 | ``` 14 | 15 | Template Body: 16 | ```html 17 | 18 | 19 | 20 | 21 | 22 | Hello -name-, 23 |

24 | I'm glad you are trying out the template feature! 25 |

26 | <%body%> 27 |

28 | I hope you are having a great day in -city- :) 29 |

30 | 31 | 32 | ``` 33 | 34 | ## With Mail Helper Class 35 | 36 | ```ruby 37 | require 'sendgrid-ruby' 38 | include SendGrid 39 | 40 | mail = SendGrid::Mail.new 41 | mail.from = Email.new(email: 'test@example.com') 42 | mail.subject = 'I\'m replacing the subject tag' 43 | personalization = Personalization.new 44 | personalization.add_to(Email.new(email: 'test@example.com')) 45 | personalization.add_substitution(Substitution.new(key: '-name-', value: 'Example User')) 46 | personalization.add_substitution(Substitution.new(key: '-city-', value: 'Denver')) 47 | mail.add_personalization(personalization) 48 | mail.template_id = '13b8f94f-bcae-4ec6-b752-70d6cb59f932' 49 | 50 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 51 | begin 52 | response = sg.client.mail._("send").post(request_body: mail.to_json) 53 | rescue Exception => e 54 | puts e.message 55 | end 56 | puts response.status_code 57 | puts response.body 58 | puts response.parsed_body 59 | puts response.headers 60 | ``` 61 | 62 | ## Without Mail Helper Class 63 | 64 | ```ruby 65 | require 'sendgrid-ruby' 66 | include SendGrid 67 | 68 | data = JSON.parse('{ 69 | "personalizations": [ 70 | { 71 | "to": [ 72 | { 73 | "email": "test@example.com" 74 | } 75 | ], 76 | "substitutions": { 77 | "-name-": "Example User", 78 | "-city-": "Denver" 79 | }, 80 | "subject": "I\'m replacing the subject tag" 81 | } 82 | ], 83 | "from": { 84 | "email": "test@example.com" 85 | }, 86 | "template_id": "13b8f94f-bcae-4ec6-b752-70d6cb59f932" 87 | }') 88 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 89 | begin 90 | response = sg.client.mail._("send").post(request_body: data) 91 | rescue Exception => e 92 | puts e.message 93 | end 94 | puts response.status_code 95 | puts response.body 96 | puts response.parsed_body 97 | puts response.headers 98 | ``` 99 | -------------------------------------------------------------------------------- /use-cases/personalizations.md: -------------------------------------------------------------------------------- 1 | # Personalizations 2 | 3 | This example demonstrates how to send multiple emails with personalizations. For further documentation, refer to [the SendGrid docs](https://docs.sendgrid.com/for-developers/sending-email/personalizations). 4 | 5 | ```ruby 6 | require 'sendgrid-ruby' 7 | include SendGrid 8 | 9 | # Note that the domain for all From addresses must match 10 | mail = Mail.new 11 | mail.from = Email.new(email: 'test@example.com') 12 | mail.add_content(Content.new(type: 'text/plain', value: 'Some test text')) 13 | mail.subject = 'Personalized Test Email' 14 | 15 | personalization = Personalization.new 16 | personalization.add_to(Email.new(email: 'test1@example.com')) 17 | mail.add_personalization(personalization) 18 | 19 | personalization2 = Personalization.new 20 | personalization2.add_to(Email.new(email: 'test2@example.com')) 21 | personalization2.add_from(Email.new(email: 'test3@example.com')) 22 | mail.add_personalization(personalization2) 23 | 24 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 25 | begin 26 | response = sg.client.mail._("send").post(request_body: mail.to_json) 27 | rescue Exception => e 28 | puts e.message 29 | end 30 | 31 | puts response.status_code 32 | puts response.body 33 | puts response.headers 34 | ``` -------------------------------------------------------------------------------- /use-cases/sms.md: -------------------------------------------------------------------------------- 1 | First, follow the [Twilio Setup](twilio-setup.md) guide for creating a Twilio account and setting up environment variables with the proper credentials. 2 | 3 | Then, install the Twilio Helper Library. Add this line to your application's Gemfile: 4 | 5 | ```bash 6 | gem 'twilio-ruby' 7 | ``` 8 | 9 | And then execute: 10 | 11 | ```bash 12 | bundle 13 | ``` 14 | 15 | Or install it yourself using: 16 | 17 | ```bash 18 | gem install twilio-ruby 19 | ``` 20 | 21 | Finally, send a message. 22 | 23 | ```ruby 24 | require 'twilio-ruby' 25 | 26 | # put your own credentials here 27 | account_sid = ENV['TWILIO_ACCOUNT_SID'] 28 | auth_token = ENV['TWILIO_AUTH_TOKEN'] 29 | 30 | # set up a client to talk to the Twilio REST API 31 | @client = Twilio::REST::Client.new account_sid, auth_token 32 | @client.api.account.messages.create( 33 | from: '+14159341234', 34 | to: '+16105557069', 35 | body: 'Hey there!' 36 | ) 37 | ``` 38 | 39 | For more information, please visit the [Twilio SMS Ruby documentation](https://www.twilio.com/docs/sms/quickstart/ruby). 40 | -------------------------------------------------------------------------------- /use-cases/transactional-templates.md: -------------------------------------------------------------------------------- 1 | # Transactional Templates 2 | 3 | For this example, we assume you have created a [dynamic transactional template](https://sendgrid.com/docs/ui/sending-email/how-to-send-an-email-with-dynamic-transactional-templates/) in the UI or via the API. Following is the template content we used for testing. 4 | 5 | Template ID (replace with your own): 6 | ```text 7 | d-2c214ac919e84170b21855cc129b4a5f 8 | ``` 9 | 10 | Email Subject: 11 | ```text 12 | {{subject}} 13 | ``` 14 | 15 | Template Body: 16 | ```html 17 | 18 | 19 | 20 | 21 | 22 | Hello {{name}}, 23 |

24 | I'm glad you are trying out the template feature! 25 |

26 | I hope you are having a great day in {{city}} :) 27 |

28 | 29 | 30 | ``` 31 | 32 | ## With Mail Helper Class 33 | ```ruby 34 | require 'sendgrid-ruby' 35 | include SendGrid 36 | 37 | mail = Mail.new 38 | mail.from = Email.new(email: 'test@example.com') 39 | personalization = Personalization.new 40 | personalization.add_to(Email.new(email: 'test@example.com')) 41 | personalization.add_dynamic_template_data({ 42 | "subject" => "Testing Templates", 43 | "name" => "Example User", 44 | "city" => "Denver" 45 | }) 46 | mail.add_personalization(personalization) 47 | mail.template_id = 'd-2c214ac919e84170b21855cc129b4a5f' 48 | 49 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 50 | begin 51 | response = sg.client.mail._("send").post(request_body: mail.to_json) 52 | rescue Exception => e 53 | puts e.message 54 | end 55 | puts response.status_code 56 | puts response.body 57 | puts response.parsed_body 58 | puts response.headers 59 | ``` 60 | 61 | ## Without Mail Helper Class 62 | 63 | ```ruby 64 | require 'sendgrid-ruby' 65 | include SendGrid 66 | 67 | data = JSON.parse('{ 68 | "personalizations": [ 69 | { 70 | "to": [ 71 | { 72 | "email": "test@example.com" 73 | } 74 | ], 75 | "dynamic_template_data": { 76 | "subject": "Testing Templates", 77 | "name": "Example User", 78 | "city": "Denver" 79 | } 80 | } 81 | ], 82 | "from": { 83 | "email": "test@example.com" 84 | }, 85 | "template_id": "d-2c214ac919e84170b21855cc129b4a5f" 86 | }') 87 | sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY']) 88 | begin 89 | response = sg.client.mail._("send").post(request_body: data) 90 | rescue Exception => e 91 | puts e.message 92 | end 93 | puts response.status_code 94 | puts response.body 95 | puts response.parsed_body 96 | puts response.headers 97 | ``` 98 | 99 | ## Adding Attachments 100 | 101 | ```ruby 102 | attachment = Attachment.new 103 | attachment.content = Base64.strict_encode64(File.open(fpath, 'rb').read) 104 | attachment.type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 105 | attachment.filename = fname 106 | attachment.disposition = 'attachment' 107 | attachment.content_id = 'Reports Sheet' 108 | mail.add_attachment(attachment) 109 | ``` 110 | 111 | Attachments must be base64 encoded, using Base64's strict_encode64 where no line feeds are added. 112 | -------------------------------------------------------------------------------- /use-cases/twilio-email.md: -------------------------------------------------------------------------------- 1 | First, follow the [Twilio Setup](twilio-setup.md) guide for creating a Twilio account and setting up environment variables with the proper credentials. 2 | 3 | Then, initialize the Twilio Email Client. 4 | 5 | ```ruby 6 | mail_client = TwilioEmail::API(username: ENV['TWILIO_API_KEY'], password: ENV['TWILIO_API_SECRET']) 7 | 8 | # or 9 | 10 | mail_client = TwilioEmail::API(username: ENV['TWILIO_ACCOUNT_SID'], password: ENV['TWILIO_AUTH_TOKEN']) 11 | ``` 12 | 13 | This client has the same interface as the `SendGrid::API` client. 14 | -------------------------------------------------------------------------------- /use-cases/twilio-setup.md: -------------------------------------------------------------------------------- 1 | ## 1. Obtain a Free Twilio Account 2 | 3 | Sign up for a free Twilio account [here](https://www.twilio.com/try-twilio?source=sendgrid-ruby). 4 | 5 | ## 2. Set Up Your Environment Variables 6 | 7 | The Twilio API allows for authentication using with either an API key/secret or your Account SID/Auth Token. You can create an API key [here](https://twil.io/get-api-key) or obtain your Account SID and Auth Token [here](https://twil.io/console). 8 | 9 | Once you have those, follow the steps below based on your operating system. 10 | 11 | ### Linux/Mac 12 | 13 | ```bash 14 | echo "export TWILIO_API_KEY='YOUR_TWILIO_API_KEY'" > twilio.env 15 | echo "export TWILIO_API_SECRET='YOUR_TWILIO_API_SECRET'" >> twilio.env 16 | 17 | # or 18 | 19 | echo "export TWILIO_ACCOUNT_SID='YOUR_TWILIO_ACCOUNT_SID'" > twilio.env 20 | echo "export TWILIO_AUTH_TOKEN='YOUR_TWILIO_AUTH_TOKEN'" >> twilio.env 21 | ``` 22 | 23 | Then: 24 | 25 | ```bash 26 | echo "twilio.env" >> .gitignore 27 | source ./twilio.env 28 | ``` 29 | 30 | ### Windows 31 | 32 | Temporarily set the environment variable (accessible only during the current CLI session): 33 | 34 | ```bash 35 | set TWILIO_API_KEY=YOUR_TWILIO_API_KEY 36 | set TWILIO_API_SECRET=YOUR_TWILIO_API_SECRET 37 | 38 | : or 39 | 40 | set TWILIO_ACCOUNT_SID=YOUR_TWILIO_ACCOUNT_SID 41 | set TWILIO_AUTH_TOKEN=YOUR_TWILIO_AUTH_TOKEN 42 | ``` 43 | 44 | Or permanently set the environment variable (accessible in all subsequent CLI sessions): 45 | 46 | ```bash 47 | setx TWILIO_API_KEY "YOUR_TWILIO_API_KEY" 48 | setx TWILIO_API_SECRET "YOUR_TWILIO_API_SECRET" 49 | 50 | : or 51 | 52 | setx TWILIO_ACCOUNT_SID "YOUR_TWILIO_ACCOUNT_SID" 53 | setx TWILIO_AUTH_TOKEN "YOUR_TWILIO_AUTH_TOKEN" 54 | ``` 55 | --------------------------------------------------------------------------------