Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sendgrid/sendgrid-csharp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9.24.0
Choose a base ref
...
head repository: sendgrid/sendgrid-csharp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref

Commits on Jul 14, 2021

  1. Copy the full SHA
    47784c7 View commit details
  2. [Librarian] Version Bump

    twilio-dx committed Jul 14, 2021
    Copy the full SHA
    5b80a2c View commit details
  3. Release 9.24.1

    twilio-dx committed Jul 14, 2021
    Copy the full SHA
    e748f31 View commit details

Commits on Jul 21, 2021

  1. Copy the full SHA
    ddf4434 View commit details

Commits on Jul 29, 2021

  1. Copy the full SHA
    596c245 View commit details
  2. docs: Updated broken Readme.md links (#1126)

    * Updated broken links following discussion on #1124
    
    * Update README.md
    
    Co-authored-by: childish-sambino <sharrison@twilio.com>
    Co-authored-by: Jennifer Mah <42650198+JenniferMah@users.noreply.github.com>
    3 people authored Jul 29, 2021
    Copy the full SHA
    be8223d View commit details

Commits on Aug 11, 2021

  1. [Librarian] Version Bump

    twilio-dx committed Aug 11, 2021
    Copy the full SHA
    610c846 View commit details
  2. Release 9.24.2

    twilio-dx committed Aug 11, 2021
    Copy the full SHA
    f79fd10 View commit details

Commits on Sep 22, 2021

  1. docs: enhancing intellisense to provide parameter limits in the descr…

    …iption… (#1133)
    
    Co-authored-by: jmounts <jmounts@spotinc.com>
    jmounts234 and jmounts authored Sep 22, 2021
    Copy the full SHA
    33bcb5d View commit details
  2. [Librarian] Version Bump

    twilio-dx committed Sep 22, 2021
    Copy the full SHA
    1c56b93 View commit details
  3. Release 9.24.3

    twilio-dx committed Sep 22, 2021
    Copy the full SHA
    e7266e8 View commit details

Commits on Sep 28, 2021

  1. Copy the full SHA
    21852f1 View commit details

Commits on Oct 8, 2021

  1. Copy the full SHA
    fe25342 View commit details

Commits on Oct 18, 2021

  1. [Librarian] Version Bump

    twilio-dx committed Oct 18, 2021
    Copy the full SHA
    fe32c95 View commit details
  2. Release 9.24.4

    twilio-dx committed Oct 18, 2021
    Copy the full SHA
    6dd50a2 View commit details

Commits on Nov 8, 2021

  1. feat: add tests & use case for From personalization (#1137)

    * feat: add tests & use case for from personalization
    Bilal Boussayoud authored Nov 8, 2021
    Copy the full SHA
    3f4316a View commit details

Commits on Nov 16, 2021

  1. Copy the full SHA
    3273dfe View commit details

Commits on Nov 17, 2021

  1. [Librarian] Version Bump

    twilio-dx committed Nov 17, 2021
    Copy the full SHA
    c3e6b73 View commit details
  2. Release 9.25.0

    twilio-dx committed Nov 17, 2021
    Copy the full SHA
    b7cb4f0 View commit details

Commits on Nov 22, 2021

  1. Copy the full SHA
    6169c51 View commit details

Commits on Nov 23, 2021

  1. chore: [Snyk] Fix for 6 vulnerabilities (#1141)

    Co-authored-by: snyk-bot <snyk-bot@snyk.io>
    Co-authored-by: Elise Shanholtz <eshanholtz@twilio.com>
    3 people authored Nov 23, 2021
    Copy the full SHA
    b6a1f16 View commit details

Commits on Dec 1, 2021

  1. [Librarian] Version Bump

    twilio-dx committed Dec 1, 2021
    Copy the full SHA
    9cb480d View commit details
  2. Release 9.25.1

    twilio-dx committed Dec 1, 2021
    Copy the full SHA
    e1a47e9 View commit details

Commits on Jan 4, 2022

  1. Copy the full SHA
    c34ac4f View commit details

Commits on Jan 12, 2022

  1. [Librarian] Version Bump

    twilio-dx committed Jan 12, 2022
    Copy the full SHA
    b301eb0 View commit details
  2. Release 9.25.2

    twilio-dx committed Jan 12, 2022
    Copy the full SHA
    732dcc9 View commit details

Commits on Feb 2, 2022

  1. Copy the full SHA
    89c0cb7 View commit details

Commits on Feb 3, 2022

  1. Copy the full SHA
    b84a988 View commit details

Commits on Feb 4, 2022

  1. chore: make Slack message consistent across all repos

    Sam Harrison committed Feb 4, 2022
    Copy the full SHA
    fe77ee9 View commit details

Commits on Feb 7, 2022

  1. Copy the full SHA
    4726253 View commit details

Commits on Feb 9, 2022

  1. [Librarian] Version Bump

    twilio-dx committed Feb 9, 2022
    Copy the full SHA
    6954661 View commit details
  2. Release 9.25.3

    twilio-dx committed Feb 9, 2022
    Copy the full SHA
    43e680e View commit details

Commits on Feb 24, 2022

  1. fix: Use the private body and header datamembers for DeserializeRespo…

    …nseBodyAsync and DeserializeResponseHeaders (#1151)
    Wind010 authored Feb 24, 2022
    Copy the full SHA
    61d84f2 View commit details

Commits on Feb 28, 2022

  1. Copy the full SHA
    2afcd7f View commit details

Commits on Mar 8, 2022

  1. Copy the full SHA
    9088127 View commit details

Commits on Mar 9, 2022

  1. [Librarian] Version Bump

    twilio-dx committed Mar 9, 2022
    Copy the full SHA
    e5e7a29 View commit details
  2. Release 9.26.0

    twilio-dx committed Mar 9, 2022
    Copy the full SHA
    75aea3a View commit details

Commits on Mar 10, 2022

  1. feat: Added mail settings attributes for bypass_spam_management, bypa…

    …ss_bou… (#1153)
    
    * Added mail settings attributes for bypass_spam_management, bypass_bounce_management and bypass_unsubscribe_management
    #1135
    
    * Documentation for bypass_spam_management, bypass_bounce_management and bypass_unsubscribe_management
    
    * Review comments- Udated right summary from the api spec
    
    Co-authored-by: Shwetha Radhakrishna <shwetha-manvinkurke@users.noreply.github.com>
    Co-authored-by: Jennifer Mah <42650198+JenniferMah@users.noreply.github.com>
    Co-authored-by: Raghav Katyal <raghavkatyal1602@gmail.com>
    4 people authored Mar 10, 2022
    Copy the full SHA
    5ed9472 View commit details

Commits on Mar 22, 2022

  1. Copy the full SHA
    badfc6a View commit details

Commits on Mar 23, 2022

  1. [Librarian] Version Bump

    twilio-dx committed Mar 23, 2022
    Copy the full SHA
    1438bab View commit details
  2. Release 9.27.0

    twilio-dx committed Mar 23, 2022
    Copy the full SHA
    b40a8ae View commit details

Commits on Mar 24, 2022

  1. chore: remove outdated announcements

    Sam Harrison committed Mar 24, 2022
    Copy the full SHA
    d5aca0f View commit details

Commits on Mar 25, 2022

  1. Copy the full SHA
    9385d27 View commit details
  2. feat: add PR title validation

    Sam Harrison committed Mar 25, 2022
    Copy the full SHA
    a02fdb5 View commit details

Commits on Apr 21, 2022

  1. test: lint PRs on synchronize events

    Since synchronize events clears the status checks, it needs to be re-run.
    Sam Harrison committed Apr 21, 2022
    Copy the full SHA
    ba65b6c View commit details

Commits on Apr 25, 2022

  1. Copy the full SHA
    57d8bf1 View commit details
  2. Copy the full SHA
    3bbfded View commit details

Commits on Apr 27, 2022

  1. Copy the full SHA
    5a034b3 View commit details

Commits on May 5, 2022

  1. Copy the full SHA
    42c8a9c View commit details

Commits on May 12, 2022

  1. chore: drop the issue links from FIRST_TIMERS doc

    Sam Harrison committed May 12, 2022
    Copy the full SHA
    14e88cd View commit details
Showing with 1,153 additions and 268 deletions.
  1. +0 −10 .github/ISSUE_TEMPLATE/config.yml
  2. +15 −0 .github/workflows/pr-lint.yml
  3. +149 −0 .github/workflows/test-and-deploy.yml
  4. +0 −30 .travis.yml
  5. +133 −0 CHANGELOG.md
  6. +0 −29 CONTRIBUTING.md
  7. +0 −1 Dockerfile
  8. +4 −4 ExampleNet45ASPNetProject/SendGrid.ASPSamples/packages.config
  9. +1 −1 ExampleNet45ASPNetProject/SendGrid.ASPWebFormsSamples/packages.config
  10. +0 −26 FIRST_TIMERS.md
  11. +0 −30 ISSUE_TEMPLATE.md
  12. +1 −1 LICENSE
  13. +1 −1 PULL_REQUEST_TEMPLATE.md
  14. +31 −22 README.md
  15. +0 −1 SendGrid.sln
  16. +13 −3 TROUBLESHOOTING.md
  17. +13 −1 USAGE.md
  18. +92 −2 USE_CASES.md
  19. +34 −0 examples/clients/clientOptions.cs
  20. +1 −1 examples/inbound-webhook-handler/Tests/Inbound.Tests/Inbound.Tests.csproj
  21. +22 −0 src/SendGrid/Helpers/Mail/Model/BypassBounceManagement.cs
  22. +22 −0 src/SendGrid/Helpers/Mail/Model/BypassSpamManagement.cs
  23. +22 −0 src/SendGrid/Helpers/Mail/Model/BypassUnsubscribeManagement.cs
  24. +18 −0 src/SendGrid/Helpers/Mail/Model/MailSettings.cs
  25. +1 −1 src/SendGrid/Helpers/Mail/Model/Personalization.cs
  26. +107 −0 src/SendGrid/Helpers/Mail/SendGridMessage.cs
  27. +1 −1 src/SendGrid/Permissions/ScopeOptions.cs
  28. +1 −1 src/SendGrid/Permissions/SendGridClientExtensions.cs
  29. +30 −30 src/SendGrid/Permissions/SendGridPermissionsBuilder.Scopes.cs
  30. +23 −5 src/SendGrid/Reliability/ReliabilitySettings.cs
  31. +4 −14 src/SendGrid/Reliability/RetryDelegatingHandler.cs
  32. +28 −13 src/SendGrid/Response.cs
  33. +3 −3 src/SendGrid/SendGrid.csproj
  34. +10 −5 src/SendGrid/SendGridClient.cs
  35. +31 −0 src/SendGrid/SendGridClientOptions.cs
  36. +194 −6 tests/SendGrid.Tests/Integration.cs
  37. +5 −5 tests/SendGrid.Tests/LicenseTests.cs
  38. +1 −1 tests/SendGrid.Tests/PermissionsBuilderTests.cs
  39. +14 −0 tests/SendGrid.Tests/PreSendEmailValidation/WhenCreatingASendGridMessage.cs
  40. +3 −2 tests/SendGrid.Tests/Reliability/ReliabilitySettingsTests.cs
  41. +2 −18 tests/SendGrid.Tests/RequiredFilesExistTest.cs
  42. +68 −0 tests/SendGrid.Tests/ResponseTests.cs
  43. +55 −0 tests/SendGrid.Tests/SendgridEmailClientTests.cs
10 changes: 0 additions & 10 deletions .github/ISSUE_TEMPLATE/config.yml

This file was deleted.

15 changes: 15 additions & 0 deletions .github/workflows/pr-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Lint PR
on:
pull_request_target:
types: [ opened, edited, synchronize, reopened ]

jobs:
validate:
name: Validate title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v4
with:
types: chore docs fix feat test misc
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
149 changes: 149 additions & 0 deletions .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
name: Test and Deploy
on:
push:
branches: [ '*' ]
tags: [ '*' ]
pull_request:
branches: [ main ]
schedule:
# Run automatically at 8AM PST Monday-Friday
- cron: '0 15 * * 1-5'
workflow_dispatch:

jobs:
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 20
env:
DOCKER_LOGIN: ${{ secrets.DOCKER_USERNAME && secrets.DOCKER_AUTH_TOKEN }}
steps:
- name: Checkout sendgrid-csharp
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Login to Docker Hub
if: env.DOCKER_LOGIN
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_AUTH_TOKEN }}

- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v1.8.2
with:
dotnet-version: '3.1.x'

- run: dotnet build -c Release
- name: Build & Test
run: make test-docker release
- run: bash <(curl -s https://codecov.io/bash)

deploy:
name: Deploy
if: success() && github.ref_type == 'tag'
needs: [ test ]
runs-on: ubuntu-latest
steps:
- name: Checkout sendgrid-csharp
uses: actions/checkout@v2

- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '3.1.x'

- name: Create GitHub Release
uses: sendgrid/dx-automator/actions/release@main
with:
footer: '**[NuGet](https://www.nuget.org/packages/Sendgrid/${version})**'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Submit metric to Datadog
uses: sendgrid/dx-automator/actions/datadog-release-metric@main
env:
DD_API_KEY: ${{ secrets.DATADOG_API_KEY }}

code-signing:
runs-on: windows-latest
needs: [ deploy ]
steps:
- name: Checkout sendgrid-csharp
uses: actions/checkout@v2

- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '3.1.x'

- name: Set up certificate
run: |
echo "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
shell: bash

- name: Set variables
id: variables
run: |
dir
echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
echo "::set-output name=KEYPAIR_NAME::gt-standard-keypair"
echo "::set-output name=CERTIFICATE_NAME::gt-certificate"
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
echo "BUILD_TOOLS_VERSION=31.0.0" >> "$GITHUB_ENV"
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
echo "C:\Program Files\DigiCert\DigiCert Keylocker Tools" >> $GITHUB_PATH
shell: bash

- name: Code signing with Software Trust Manager
id: SSMClientToolSetup
uses: digicert/ssm-code-signing@v0.0.2
env:
SM_API_KEY: ${{ env.SM_API_KEY }}
SM_CLIENT_CERT_PASSWORD: ${{ env.SM_CLIENT_CERT_PASSWORD }}
SM_CLIENT_CERT_FILE: ${{ env.SM_CLIENT_CERT_FILE }}

- run: echo “The config file path ${{ steps.SSMClientToolSetup.outputs.PKCS11_CONFIG }}”

- name: Setup Keylocker KSP on windows
run: |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o Keylockertools-windows-x64.msi
msiexec /i Keylockertools-windows-x64.msi /quiet /qn
smksp_registrar.exe list
smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
shell: cmd

- name: Certificates Sync
run: |
smctl windows certsync
shell: cmd

- name: Signing using Nuget
run: |
dotnet pack -c Release
nuget sign **/*.nupkg -Timestamper http://timestamp.digicert.com -outputdirectory .\NugetSigned -CertificateFingerprint ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} -HashAlgorithm SHA256 -Verbosity detailed -Overwrite
nuget push **/*.nupkg -ApiKey ${{ secrets.NUGET_API_KEY }} -Source https://api.nuget.org/v3/index.json -SkipDuplicate
notify-on-failure:
name: Slack notify on failure
if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag')
needs: [ test, deploy ]
runs-on: ubuntu-latest
steps:
- uses: rtCamp/action-slack-notify@v2
env:
SLACK_COLOR: failure
SLACK_ICON_EMOJI: ':github:'
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) }}
SLACK_TITLE: Action Failure - ${{ github.repository }}
SLACK_USERNAME: GitHub Actions
SLACK_MSG_AUTHOR: twilio-dx
SLACK_FOOTER: Posted automatically using GitHub Actions
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
MSG_MINIMAL: true
30 changes: 0 additions & 30 deletions .travis.yml

This file was deleted.

133 changes: 133 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,139 @@
# Change Log
All notable changes to this project will be documented in this file.

[2024-04-02] Version 9.29.3
---------------------------
**Library - Chore**
- [PR #1203](https://github.com/sendgrid/sendgrid-csharp/pull/1203): correct code signing command. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!


[2024-02-14] Version 9.29.2
---------------------------
**Library - Chore**
- [PR #1202](https://github.com/sendgrid/sendgrid-csharp/pull/1202): corrected nuget push. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #1201](https://github.com/sendgrid/sendgrid-csharp/pull/1201): added code-signing workflow. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #1199](https://github.com/sendgrid/sendgrid-csharp/pull/1199): adding skip-duplicate flag. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #1198](https://github.com/sendgrid/sendgrid-csharp/pull/1198): Update test-and-deploy.yml. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #1197](https://github.com/sendgrid/sendgrid-csharp/pull/1197): import-certificate added as prerequisite for deploy. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #1196](https://github.com/sendgrid/sendgrid-csharp/pull/1196): added import-certificate workflow. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!
- [PR #1193](https://github.com/sendgrid/sendgrid-csharp/pull/1193): Update LICENSE. Thanks to [@shrutiburman](https://github.com/shrutiburman)!


[2023-12-06] Version 9.29.1
---------------------------
**Library - Fix**
- [PR #1191](https://github.com/sendgrid/sendgrid-csharp/pull/1191): update deployment pipeline to add signing step. Thanks to [@shrutiburman](https://github.com/shrutiburman)!


[2023-12-01] Version 9.29.0
---------------------------
**Library - Feature**
- [PR #1190](https://github.com/sendgrid/sendgrid-csharp/pull/1190): Add data residency for eu and global regions. Thanks to [@shrutiburman](https://github.com/shrutiburman)!


[2022-08-10] Version 9.28.1
---------------------------
**Library - Docs**
- [PR #1181](https://github.com/sendgrid/sendgrid-csharp/pull/1181): Example of adding a WebProxy using DI. Thanks to [@mortenbock](https://github.com/mortenbock)!

**Library - Fix**
- [PR #1180](https://github.com/sendgrid/sendgrid-csharp/pull/1180): Use httpErrorAsException when passed as parameter to SendGridClient constructor. Thanks to [@mortenbock](https://github.com/mortenbock)!

**Library - Miscellaneous**
- [PR #1178](https://github.com/sendgrid/sendgrid-csharp/pull/1178): bump Newtonsoft.Json from 11.0.2 to 13.0.1 in /examples/inbound-webhook-handler/Tests/Inbound.Tests. Thanks to [@dependabot](https://github.com/dependabot)!

**Library - Test**
- [PR #1179](https://github.com/sendgrid/sendgrid-csharp/pull/1179): Adding misc as PR type. Thanks to [@rakatyal](https://github.com/rakatyal)!


[2022-05-18] Version 9.28.0
---------------------------
**Library - Docs**
- [PR #1176](https://github.com/sendgrid/sendgrid-csharp/pull/1176): Update to align with SendGrid Support. Thanks to [@garethpaul](https://github.com/garethpaul)!

**Library - Chore**
- [PR #1174](https://github.com/sendgrid/sendgrid-csharp/pull/1174): Security upgrade Newtonsoft.Json from 9.0.1 to 13.0.1. Thanks to [@svcprodsec-sendgrid](https://github.com/svcprodsec-sendgrid)!
- [PR #1173](https://github.com/sendgrid/sendgrid-csharp/pull/1173): Security upgrade Newtonsoft.Json from 9.0.1 to 13.0.1. Thanks to [@svcprodsec-sendgrid](https://github.com/svcprodsec-sendgrid)!
- [PR #1175](https://github.com/sendgrid/sendgrid-csharp/pull/1175): Security upgrade Newtonsoft.Json from 10.0.3 to 13.0.1. Thanks to [@svcprodsec-sendgrid](https://github.com/svcprodsec-sendgrid)!

**Library - Feature**
- [PR #1169](https://github.com/sendgrid/sendgrid-csharp/pull/1169): Add support for multiple Reply-Tos. Thanks to [@RyanFlemingOlo](https://github.com/RyanFlemingOlo)!


[2022-03-23] Version 9.27.0
---------------------------
**Library - Fix**
- [PR #1168](https://github.com/sendgrid/sendgrid-csharp/pull/1168): fallback to private body and headers for response deserialization. Thanks to [@childish-sambino](https://github.com/childish-sambino)!

**Library - Feature**
- [PR #1153](https://github.com/sendgrid/sendgrid-csharp/pull/1153): Added mail settings attributes for bypass_spam_management, bypass_bou…. Thanks to [@asos-vinodpatil](https://github.com/asos-vinodpatil)!


[2022-03-09] Version 9.26.0
---------------------------
**Library - Feature**
- [PR #1156](https://github.com/sendgrid/sendgrid-csharp/pull/1156): make RetriableServerErrorStatusCodes public. Thanks to [@maxkoshevoi](https://github.com/maxkoshevoi)!

**Library - Chore**
- [PR #1166](https://github.com/sendgrid/sendgrid-csharp/pull/1166): push Datadog Release Metric upon deploy success. Thanks to [@eshanholtz](https://github.com/eshanholtz)!

**Library - Fix**
- [PR #1151](https://github.com/sendgrid/sendgrid-csharp/pull/1151): Use the private body and header datamembers for DeserializeResponseBodyAsync and DeserializeResponseHeaders. Thanks to [@Wind010](https://github.com/Wind010)!


[2022-02-09] Version 9.25.3
---------------------------
**Library - Chore**
- [PR #1161](https://github.com/sendgrid/sendgrid-csharp/pull/1161): add gh release to workflow. Thanks to [@shwetha-manvinkurke](https://github.com/shwetha-manvinkurke)!
- [PR #1158](https://github.com/sendgrid/sendgrid-csharp/pull/1158): merge test and deploy workflows. Thanks to [@shwetha-manvinkurke](https://github.com/shwetha-manvinkurke)!


[2022-01-12] Version 9.25.2
---------------------------
**Library - Chore**
- [PR #1152](https://github.com/sendgrid/sendgrid-csharp/pull/1152): update license year. Thanks to [@JenniferMah](https://github.com/JenniferMah)!


[2021-12-01] Version 9.25.1
---------------------------
**Library - Chore**
- [PR #1141](https://github.com/sendgrid/sendgrid-csharp/pull/1141): [Snyk] Fix for 6 vulnerabilities. Thanks to [@svcprodsec-sendgrid](https://github.com/svcprodsec-sendgrid)!
- [PR #1142](https://github.com/sendgrid/sendgrid-csharp/pull/1142): migrate to GitHub Actions. Thanks to [@eshanholtz](https://github.com/eshanholtz)!


[2021-11-17] Version 9.25.0
---------------------------
**Library - Chore**
- [PR #1140](https://github.com/sendgrid/sendgrid-csharp/pull/1140): bump ecdsa-dotnet version. Thanks to [@JenniferMah](https://github.com/JenniferMah)!

**Library - Feature**
- [PR #1137](https://github.com/sendgrid/sendgrid-csharp/pull/1137): add tests & use case for From personalization. Thanks to [@beebzz](https://github.com/beebzz)!


[2021-10-18] Version 9.24.4
---------------------------
**Library - Docs**
- [PR #1134](https://github.com/sendgrid/sendgrid-csharp/pull/1134): improve signed webhook event validation docs. Thanks to [@shwetha-manvinkurke](https://github.com/shwetha-manvinkurke)!


[2021-09-22] Version 9.24.3
---------------------------
**Library - Docs**
- [PR #1133](https://github.com/sendgrid/sendgrid-csharp/pull/1133): enhancing intellisense to provide parameter limits in the description…. Thanks to [@jmounts234](https://github.com/jmounts234)!


[2021-08-11] Version 9.24.2
---------------------------
**Library - Docs**
- [PR #1126](https://github.com/sendgrid/sendgrid-csharp/pull/1126): Updated broken Readme.md links. Thanks to [@DanielHolland](https://github.com/DanielHolland)!


[2021-07-14] Version 9.24.1
---------------------------
**Library - Docs**
- [PR #1123](https://github.com/sendgrid/sendgrid-csharp/pull/1123): fix mistake in README.md. Thanks to [@hakuna-matata-in](https://github.com/hakuna-matata-in)!


[2021-06-21] Version 9.24.0
---------------------------
**Library - Chore**
29 changes: 0 additions & 29 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -2,8 +2,6 @@ Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid o

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.

- [Feature Request](#feature-request)
- [Submit a Bug Report](#submit-a-bug-report)
- [Improvements to the Codebase](#improvements-to-the-codebase)
- [Understanding the Code Base](#understanding-the-codebase)
- [Testing](#testing)
@@ -13,33 +11,6 @@ All third party contributors acknowledge that any contributions they provide wil

There are a few ways to contribute, which we'll enumerate below:

<a name="feature-request"></a>
## Feature Request

If you'd like to make a feature request, please read this section.

The GitHub issue tracker is the preferred channel for library feature requests, but please respect the following restrictions:

- Please **search for existing issues** in order to ensure we don't have duplicate bugs/feature requests.
- Please be respectful and considerate of others when commenting on issues

<a name="submit-a-bug-report"></a>
## Submit a Bug Report

Note: DO NOT include your credentials in ANY code examples, descriptions, or media you make public.

A software bug is a demonstrable issue in the code base. In order for us to diagnose the issue and respond as quickly as possible, please add as much detail as possible into your bug report.

Before you decide to create a new issue, please try the following:

1. Check the GitHub issues tab if the identified issue has already been reported, if so, please add a +1 to the existing post.
2. Update to the latest version of this code and check if the issue has already been fixed
3. Copy and fill in the Bug Report Template we have provided below

### Please use our Bug Report Template

In order to make the process easier, we've included a [sample bug report template](ISSUE_TEMPLATE.md).

<a name="improvements-to-the-codebase"></a>
## Improvements to the Codebase

1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -14,7 +14,6 @@ RUN apt-get update \
COPY prism/prism/nginx/cert.crt /usr/local/share/ca-certificates/cert.crt
RUN update-ca-certificates

WORKDIR /app
COPY . .

RUN make install
8 changes: 4 additions & 4 deletions ExampleNet45ASPNetProject/SendGrid.ASPSamples/packages.config
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@
<package id="Antlr" version="3.4.1.9004" targetFramework="net452" />
<package id="bootstrap" version="3.4.1" targetFramework="net452" />
<package id="EntityFramework" version="6.1.3" targetFramework="net452" />
<package id="jQuery" version="1.10.2" targetFramework="net452" />
<package id="jQuery.Validation" version="1.11.1" targetFramework="net452" />
<package id="jQuery" version="3.5.0" targetFramework="net452" />
<package id="jQuery.Validation" version="1.19.3" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights" version="2.2.0" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.0.6" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.2.0" targetFramework="net452" />
@@ -22,7 +22,7 @@
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.0" targetFramework="net452" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net452" />
<package id="Microsoft.Net.Compilers" version="1.0.0" targetFramework="net452" developmentDependency="true" />
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Owin" version="4.1.1" targetFramework="net452" />
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Owin.Security.Cookies" version="3.0.1" targetFramework="net452" />
@@ -33,7 +33,7 @@
<package id="Microsoft.Owin.Security.Twitter" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net452" />
<package id="Modernizr" version="2.6.2" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net452" />
<package id="Owin" version="1.0" targetFramework="net452" />
<package id="Respond" version="1.2.0" targetFramework="net452" />
<package id="Sendgrid" version="9" targetFramework="net452" />
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.7" targetFramework="net461" />
<package id="Microsoft.Net.Compilers" version="2.3.2" targetFramework="net461" developmentDependency="true" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net461" />
<package id="Sendgrid" version="9.9.0" targetFramework="net461" />
<package id="System.Net.Http" version="4.3.4" targetFramework="net461" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
26 changes: 0 additions & 26 deletions FIRST_TIMERS.md
Original file line number Diff line number Diff line change
@@ -51,29 +51,3 @@ git push origin <topic-branch-name>
## Important notice

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.

## Repositories with Open, Easy, Help Wanted, Issue Filters

* [Python SDK](https://github.com/sendgrid/sendgrid-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [PHP SDK](https://github.com/sendgrid/sendgrid-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [C# SDK](https://github.com/sendgrid/sendgrid-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Ruby SDK](https://github.com/sendgrid/sendgrid-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Node.js SDK](https://github.com/sendgrid/sendgrid-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Java SDK](https://github.com/sendgrid/sendgrid-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Go SDK](https://github.com/sendgrid/sendgrid-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Python SMTPAPI Client](https://github.com/sendgrid/smtpapi-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [PHP SMTPAPI Client](https://github.com/sendgrid/smtpapi-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [C# SMTPAPI Client](https://github.com/sendgrid/smtpapi-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Ruby SMTPAPI Client](https://github.com/sendgrid/smtpapi-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Node.js SMTPAPI Client](https://github.com/sendgrid/smtpapi-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Java SMTPAPI Client](https://github.com/sendgrid/smtpapi-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Go SMTPAPI Client](https://github.com/sendgrid/smtpapi-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Python HTTP Client](https://github.com/sendgrid/python-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [PHP HTTP Client](https://github.com/sendgrid/php-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [C# HTTP Client](https://github.com/sendgrid/csharp-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Java HTTP Client](https://github.com/sendgrid/java-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Ruby HTTP Client](https://github.com/sendgrid/ruby-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Go HTTP Client](https://github.com/sendgrid/rest/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Open API Definition](https://github.com/sendgrid/sendgrid-oai/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [DX Automator](https://github.com/sendgrid/dx-automator/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
* [Documentation](https://github.com/sendgrid/docs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22)
30 changes: 0 additions & 30 deletions ISSUE_TEMPLATE.md

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (C) 2021, Twilio SendGrid, Inc. <help@twilio.com>
Copyright (C) 2024, Twilio SendGrid, Inc. <help@twilio.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
2 changes: 1 addition & 1 deletion PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ We appreciate the effort for this pull request but before that please make sure
Please format the PR title appropriately based on the type of change:
<type>[!]: <description>
Where <type> is one of: docs, chore, feat, fix, test.
Where <type> is one of: docs, chore, feat, fix, test, misc.
Add a '!' after the type for breaking changes (e.g. feat!: new breaking feature).
**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.**
53 changes: 31 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
![SendGrid Logo](twilio_sendgrid_logo.png)

[![BuildStatus](https://travis-ci.com/sendgrid/sendgrid-csharp.png?branch=main)](https://travis-ci.com/sendgrid/sendgrid-csharp)
[![Test and Deploy](https://github.com/sendgrid/sendgrid-csharp/actions/workflows/test-and-deploy.yml/badge.svg)](https://github.com/sendgrid/sendgrid-csharp/actions/workflows/test-and-deploy.yml)
[![NuGet](https://img.shields.io/nuget/v/SendGrid.svg)](https://www.nuget.org/packages/SendGrid)
[![Email Notifications Badge](https://dx.sendgrid.com/badge/csharp)](https://dx.sendgrid.com/newsletter/csharp)
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid)
[![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/sendgrid-csharp.svg)](https://github.com/sendgrid/sendgrid-csharp/graphs/contributors)
[![Open Source Helpers](https://www.codetriage.com/sendgrid/sendgrid-csharp/badges/users.svg)](https://www.codetriage.com/sendgrid/sendgrid-csharp)

# Announcements
**The default branch name for this repository has been changed to `main` as of 07/27/2020.**

* Subscribe to email [notifications](https://dx.sendgrid.com/newsletter/csharp) for releases and breaking changes.
* Send SMS messages with [Twilio](USE_CASES.md#sms).

# Overview
@@ -20,12 +17,8 @@

Version 9.X.X+ of this library provides full support for all Twilio SendGrid [Web API v3](https://sendgrid.com/docs/API_Reference/api_v3.html) endpoints, including the new [v3 /mail/send](https://sendgrid.com/blog/introducing-v3mailsend-sendgrids-new-mail-endpoint).

We want this library to be community driven, and Twilio SendGrid led. We need your help to realize this goal. To help make sure we are building the right things in the right order, we ask that you create [issues](https://github.com/sendgrid/sendgrid-csharp/issues) and [pull requests](CONTRIBUTING.md) or simply upvote or comment on existing issues or pull requests.

For updates to this library, see our [CHANGELOG](CHANGELOG.md) and [releases](https://github.com/sendgrid/sendgrid-csharp/releases).

Subscribe to email [release notifications](https://dx.sendgrid.com/newsletter/csharp) to receive emails about releases and breaking changes.

We appreciate your continued support, thank you!

# Table of Contents
@@ -46,6 +39,7 @@ We appreciate your continued support, thank you!
* [How to Contribute](#how-to-contribute)
* [Troubleshooting](#troubleshooting)
* [About](#about)
* [Support](#support)
* [License](#license)

# Installation
@@ -79,7 +73,7 @@ Setup Environment Variables using the UI:
Setup Environment Variables using CMD:

1. Run CMD as administrator
2. set SENDGRID_API_KEY "YOUR_API_KEY"
2. set SENDGRID_API_KEY="YOUR_API_KEY"

Here are a few examples to get and set API Keys programmatically:

@@ -139,7 +133,7 @@ class Program
}
```

After executing the above code, `response.StatusCode` should be `202` and you should have an email in the inbox of the `to` recipient. You can check the status of your email [in the UI](https://app.sendgrid.com/email_activity?). Alternatively, we can post events to a URL of your choice using our [Event Webhook](https://sendgrid.com/docs/API_Reference/Webhooks/event.html). This gives you data about the events that occur as Twilio SendGrid processes your email.
After executing the above code, `response.StatusCode` should be `202` and you should have an email in the inbox of the `to` recipient. You can check the status of your email [in the UI](https://app.sendgrid.com/email_activity?). Alternatively, we can post events to a URL of your choice using our [Event Webhook](https://docs.sendgrid.com/for-developers/tracking-events/getting-started-event-webhook). This gives you data about the events that occur as Twilio SendGrid processes your email.

For more advanced cases, you can build the SendGridMessage object yourself with these minimum required settings:

@@ -191,15 +185,6 @@ class Program
}
```

<a name="proxy"></a>
## Web Proxy

```csharp
var apiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var proxy = new WebProxy("http://proxy:1337");
var client = new SendGridClient(proxy, apiKey);
```

## HttpClientFactory + Microsoft.Extensions.DependencyInjection

> [SendGrid.Extensions.DependencyInjection](https://www.nuget.org/packages/SendGrid.Extensions.DependencyInjection) is required
@@ -240,9 +225,33 @@ class Program
}
```

<a name="proxy"></a>
## Web Proxy

```csharp
var apiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var proxy = new WebProxy("http://proxy:1337");
var client = new SendGridClient(proxy, apiKey);
```

Or when using DependencyInjection

```csharp
services.AddSendGrid(options =>
{
options.ApiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
})
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{
Proxy = new WebProxy(new Uri("http://proxy:1337")),
UseProxy = true
});
```


# Usage

- [Twilio SendGrid Docs](https://sendgrid.com/docs/API_Reference/api_v3.html)
- [Twilio SendGrid Docs](https://docs.sendgrid.com/api-reference/)
- [Library Usage Docs](USAGE.md)
- [Example Code - .NET Core](ExampleCoreProject)
- [Example Code - .NET 4.5.2+](ExampleNet45Project)
@@ -272,9 +281,9 @@ Please see our [troubleshooting guide](TROUBLESHOOTING.md) for common library is

sendgrid-csharp is maintained and funded by Twilio SendGrid, Inc. The names and logos for sendgrid-csharp are trademarks of Twilio SendGrid, Inc.

If you need help installing or using the library, please check the [Twilio SendGrid Support Help Center](https://support.sendgrid.com).
# Support

If you've instead found a bug in the library or would like new features added, go ahead and open issues or pull requests against this repo!
If you need help using SendGrid, please check the [Twilio SendGrid Support Help Center](https://support.sendgrid.com).

# License
[The MIT License (MIT)](LICENSE)
1 change: 0 additions & 1 deletion SendGrid.sln
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
.env_sample = .env_sample
.gitignore = .gitignore
.travis.yml = .travis.yml
CHANGELOG.md = CHANGELOG.md
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
CONTRIBUTING.md = CONTRIBUTING.md
16 changes: 13 additions & 3 deletions TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
@@ -2,8 +2,6 @@

If you have a non-library Twilio SendGrid issue, please contact our [support team](https://support.sendgrid.com).

If you can't find a solution below, please open an [issue](https://github.com/sendgrid/sendgrid-csharp/issues).


## Table of Contents

@@ -19,6 +17,7 @@ If you can't find a solution below, please open an [issue](https://github.com/se
* [Versioning Convention](#versioning)
* [Viewing the Request Body](#request-body)
* [UI requests are failing](#ui-requests)
* [Verifying Event Webhooks](#signed-webhooks)

<a name="v2"></a>
## Continue Using the v2 API
@@ -135,7 +134,7 @@ Please review [our guide](https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/

v9 of this SDK is a complete rewrite that includes the removal of dynamic dependencies, a new Mail Helper and support for .NET Standard 1.3.

Please begin at the [README](https://github.com/sendgrid/sendgrid-csharp) and if you need further assistance, please [create an issue on GitHub](https://github.com/sendgrid/sendgrid-csharp/issues).
Please begin at the [README](https://github.com/sendgrid/sendgrid-csharp).

<a name="missing"></a>
## Missing Classes
@@ -204,3 +203,14 @@ var response = await client.SendEmailAsync(msg).ConfigureAwait(false);
If you are running a newer versions of .NET you can turn on a couple different Roslyn based analyzers that will trigger build errors if you're not calling `.ConfigureAwait(false)` on your async methods.

`Roslynator.Analyzers` can be installed through NuGet or as a VS plugin, but if you use the plugin then the analyzers won't run on build servers and trigger build errors as the NuGet package would. (thanks to [xt0rted](https://github.com/xt0rted) for this tip!)

<a name="signed-webhooks"></a>
## Signed Webhook Verification

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-csharp library can help you verify these Signed Event Webhooks.

You can find the end-to-end usage example and the tests [here](examples/eventwebhook).
If you are still having trouble getting the validation to work, follow the following instructions:
- Be sure to use the *raw* payload for validation
- Be sure to include a trailing carriage return and newline in your payload
- In case of multi-event webhooks, make sure you include the trailing newline and carriage return after *each* event
14 changes: 13 additions & 1 deletion USAGE.md
Original file line number Diff line number Diff line change
@@ -2444,6 +2444,9 @@ This endpoint allows you to send email over Twilio SendGrid's v3 Web API, the mo
* Top level parameters are referred to as "global".
* Individual fields within the personalizations array will override any other global, or message level, parameters that are defined outside of personalizations.

* Note: bypass_bounce_management, bypass_spam_management, and bypass_unsubscribe_management cannot
* be combined with bypass_list_management

For an overview of the v3 Mail Send endpoint, please visit our [v3 API Reference](https://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/index.html)

For more detailed information about how to use the v3 Mail Send endpoint, please visit our [Classroom](https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/index.html).
@@ -2501,7 +2504,16 @@ string data = @"{
},
'bypass_list_management': {
'enable': true
},
},
'bypass_spam_management': {
'enable': true
},
'bypass_bounce_management': {
'enable': true
},
'bypass_unsubscribe_management': {
'enable': true
},
'footer': {
'enable': true,
'html': '<p>Thanks</br>The Twilio SendGrid Team</p>',
94 changes: 92 additions & 2 deletions USE_CASES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
This document provides examples for specific use cases. Please [open an issue](https://github.com/sendgrid/sendgrid-sharp/issues) or make a pull request for any use cases you would like us to document here. Thank you!
This document provides examples for specific use cases.

# Table of Contents

@@ -8,6 +8,7 @@ This document provides examples for specific use cases. Please [open an issue](h
- [Send a Single Email to Multiple Recipients](#send-a-single-email-to-multiple-recipients)
- [Send a Single Email to a Single Recipient](#send-a-single-email-to-a-single-recipient)
- [Send Multiple Emails to Multiple Recipients](#send-multiple-emails-to-multiple-recipients)
- [Send Multiple Emails with Personalizations](#send-multiple-emails-with-personalizations)
- [Transactional Templates](#transactional-templates)
- [With Mail Helper Class](#with-mail-helper-class)
- [Without Mail Helper Class](#without-mail-helper-class)
@@ -318,6 +319,14 @@ namespace Example
msg.SetBccSetting(true, "test@example.com");

// Note: Bypass Spam, Bounce, and Unsubscribe management cannot be combined with Bypass List Management
msg.BypassSpamManagement(true);

msg.BypassBounceManagement(true);

msg.BypassUnsubscribeManagement(true);

// OR
msg.SetBypassListManagement(true);

msg.SetFooterSetting(true, "Some Footer HTML", "Some Footer Text");
@@ -492,6 +501,63 @@ namespace Example
}
```

<a name="multipleemailspersonalization"></a>
# Send Multiple Emails with Personalizations

```csharp
using SendGrid;
using SendGrid.Helpers.Mail;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Example
{
internal class Example
{
private static void Main()
{
Execute().Wait();
}

static async Task Execute()
{
var apiKey = Environment.GetEnvironmentVariable("NAME_OF_THE_ENVIRONMENT_VARIABLE_FOR_YOUR_SENDGRID_KEY");
var client = new SendGridClient(apiKey);
var from = new EmailAddress("test@example.com");
var subject = "Hello from Twilio SendGrid!";

// Note that the domain for all from addresses must match
var msg = new SendGridMessage();
msg.Subject = subject;
msg.AddContent(MimeType.Text, "Easy to use, even with C#!");
msg.SetFrom(from);

msg.Personalizations = new List<Personalization>() {
new Personalization() {
Tos = new List<EmailAddress>() {
new EmailAddress("test1@example.com")
}
},
new Personalization() {
Tos = new List<EmailAddress>() {
new EmailAddress("test2@example.com")
},
From = new EmailAddress("test3@example.com")
},
};
var response = await client.SendEmailAsync(msg);

Console.WriteLine(msg.Serialize());
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Headers.ToString());
Console.WriteLine("\n\nPress any key to exit.");
Console.ReadLine();
}
}
}
```

<a name="transactional-templates"></a>
# Transactional Templates

@@ -854,6 +920,30 @@ var client = new SendGridClient(options);

```

The SendGridClientOptions object can also be used to set the region to "eu", which will send the
request to https://api.eu.sendgrid.com/. By default it is set to https://api.sendgrid.com/, e.g.

```csharp

var options = new SendGridClientOptions
{
ApiKey = Environment.GetEnvironmentVariable("NAME_OF_THE_ENVIRONMENT_VARIABLE_FOR_YOUR_SENDGRID_KEY"),
ReliabilitySettings = new ReliabilitySettings(2, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(3)),
Host = "Your-Host",
UrlPath = "Url-Path",
Version = "3",
RequestHeaders = new Dictionary<string, string>() {{"header-key", "header-value"}}
};
options.SetDataResidency("eu");
var client = new SendGridClient(options);

OR

options.SetDataResidency("global");
var client = new SendGridClient(options);

```

<a name="domain-authentication"></a>
# How to Setup a Domain Authentication

@@ -1087,4 +1177,4 @@ builder.Include(myScopes);
builder.Include("newsletter.read");
await client.CreateApiKey(builder, "Mail send, Alerts & Newletter read");
```
```
34 changes: 34 additions & 0 deletions examples/clients/clientOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Newtonsoft.Json;
using SendGrid;
using SendGrid.Helpers.Mail; // If you are using the Mail Helper
using System;


var apiKey = Environment.GetEnvironmentVariable("NAME_OF_THE_ENVIRONMENT_VARIABLE_FOR_YOUR_SENDGRID_KEY");
var options = new SendGridClientOptions();


////////////////////////////////////////////////////////
// Available Sendgrid Client Options to set region as "eu"

var client_option_region = "eu";
options.SetDataResidency(client_option_region);
var client = new SendGridClient(options);
var response = await client.RequestAsync(method: SendGridClient.Method.GET, urlPath: "clients/stats");
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Body.ReadAsStringAsync().Result);
Console.WriteLine(response.Headers.ToString());
Console.ReadLine();

////////////////////////////////////////////////////////
// Available Sendgrid Client Options to set region as "global"

var client_option_region = "global";
options.SetDataResidency(client_option_region);
var client = new SendGridClient(options);
var response = await client.RequestAsync(method: SendGridClient.Method.GET, urlPath: "clients/stats");
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Body.ReadAsStringAsync().Result);
Console.WriteLine(response.Headers.ToString());
Console.ReadLine();

Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.1.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Shouldly" Version="3.0.1" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
22 changes: 22 additions & 0 deletions src/SendGrid/Helpers/Mail/Model/BypassBounceManagement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// <copyright file="BypassListManagement.cs" company="Twilio SendGrid">
// Copyright (c) Twilio SendGrid. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// </copyright>

using Newtonsoft.Json;

namespace SendGrid.Helpers.Mail
{
/// <summary>
/// Allows you to bypass the bounce list to ensure that the email is delivered to recipients. Spam report and unsubscribe lists will still be checked; addresses on these other lists will not receive the message.
/// </summary>
[JsonObject(IsReference = false)]
public class BypassBounceManagement
{
/// <summary>
/// Gets or sets a value indicating whether this setting is enabled.
/// </summary>
[JsonProperty(PropertyName = "enable")]
public bool Enable { get; set; }
}
}
22 changes: 22 additions & 0 deletions src/SendGrid/Helpers/Mail/Model/BypassSpamManagement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// <copyright file="BypassListManagement.cs" company="Twilio SendGrid">
// Copyright (c) Twilio SendGrid. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// </copyright>

using Newtonsoft.Json;

namespace SendGrid.Helpers.Mail
{
/// <summary>
/// Allows you to bypass the spam report list to ensure that the email is delivered to recipients. Bounce and unsubscribe lists will still be checked; addresses on these other lists will not receive the message.
/// </summary>
[JsonObject(IsReference = false)]
public class BypassSpamManagement
{
/// <summary>
/// Gets or sets a value indicating whether this setting is enabled.
/// </summary>
[JsonProperty(PropertyName = "enable")]
public bool Enable { get; set; }
}
}
22 changes: 22 additions & 0 deletions src/SendGrid/Helpers/Mail/Model/BypassUnsubscribeManagement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// <copyright file="BypassListManagement.cs" company="Twilio SendGrid">
// Copyright (c) Twilio SendGrid. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// </copyright>

using Newtonsoft.Json;

namespace SendGrid.Helpers.Mail
{
/// <summary>
/// Allows you to bypass the global unsubscribe list to ensure that the email is delivered to recipients. Bounce and spam report lists will still be checked; addresses on these other lists will not receive the message. This filter applies only to global unsubscribes and will not bypass group unsubscribes.
/// </summary>
[JsonObject(IsReference = false)]
public class BypassUnsubscribeManagement
{
/// <summary>
/// Gets or sets a value indicating whether this setting is enabled.
/// </summary>
[JsonProperty(PropertyName = "enable")]
public bool Enable { get; set; }
}
}
18 changes: 18 additions & 0 deletions src/SendGrid/Helpers/Mail/Model/MailSettings.cs
Original file line number Diff line number Diff line change
@@ -25,6 +25,24 @@ public class MailSettings
[JsonProperty(PropertyName = "bypass_list_management")]
public BypassListManagement BypassListManagement { get; set; }

/// <summary>
/// Gets or sets the bypass of spam report list to ensure that the email is delivered to recipients. Bounce and unsubscribe lists will still be checked; addresses on these other lists will not receive the message.
/// </summary>
[JsonProperty(PropertyName = "bypass_spam_management")]
public BypassSpamManagement BypassSpamManagement { get; set; }

/// <summary>
/// Gets or sets the bypass the bounce list to ensure that the email is delivered to recipients. Spam report and unsubscribe lists will still be checked; addresses on these other lists will not receive the message.
/// </summary>
[JsonProperty(PropertyName = "bypass_bounce_management")]
public BypassBounceManagement BypassBounceManagement { get; set; }

/// <summary>
/// Gets or sets the bypass the global unsubscribe list to ensure that the email is delivered to recipients. Bounce and spam report lists will still be checked; addresses on these other lists will not receive the message. This filter applies only to global unsubscribes and will not bypass group unsubscribes.
/// </summary>
[JsonProperty(PropertyName = "bypass_unsubscribe_management")]
public BypassUnsubscribeManagement BypassUnsubscribeManagement { get; set; }

/// <summary>
/// Gets or sets the default footer that you would like appended to the bottom of every email.
/// </summary>
2 changes: 1 addition & 1 deletion src/SendGrid/Helpers/Mail/Model/Personalization.cs
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ public class Personalization
/// <summary>
/// Gets or sets the template data object following the pattern "template data key":"template data value". All are assumed to be strings. These key value pairs will apply to the content of your template email, in addition to the subject and reply-to parameters.
/// </summary>
[JsonProperty(PropertyName = "dynamic_template_data", IsReference = false)]
[JsonProperty(PropertyName = "dynamic_template_data", IsReference = false, ItemIsReference = false)]
public object TemplateData { get; set; }
}
}
107 changes: 107 additions & 0 deletions src/SendGrid/Helpers/Mail/SendGridMessage.cs
Original file line number Diff line number Diff line change
@@ -138,6 +138,12 @@ public class SendGridMessage
[JsonProperty(PropertyName = "reply_to")]
public EmailAddress ReplyTo { get; set; }

/// <summary>
/// Gets or sets a list of objects of email objects containing the email address and name of the individuals who should receive responses to your email.
/// </summary>
[JsonProperty(PropertyName = "reply_to_list", IsReference = false)]
public List<EmailAddress> ReplyTos { get; set; }

/// <summary>
/// Add a recipient email.
/// </summary>
@@ -318,6 +324,50 @@ public void AddHeaders(Dictionary<string, string> headers, int personalizationIn
personalization.Headers.Union(headers).ToDictionary(pair => pair.Key, pair => pair.Value);
}

/// <summary>
/// Add a reply-to email.
/// </summary>
/// <param name="email">Specify the recipient's email.</param>
/// <param name="name">Specify the recipient's name.</param>
/// <exception cref="System.ArgumentNullException">Thrown when the email parameter is null or whitespace</exception>
public void AddReplyTo(string email, string name = null)
{
if (string.IsNullOrWhiteSpace(email))
throw new ArgumentNullException("email");

this.AddReplyTo(new EmailAddress(email, name));
}

/// <summary>
/// Add a reply-to email.
/// </summary>
/// <param name="email">An email recipient that may contain the recipient’s name, but must always contain the recipient’s email.</param>
/// <exception cref="System.ArgumentNullException">Thrown when the email parameter is null</exception>
public void AddReplyTo(EmailAddress email)
{
if (email == null)
throw new ArgumentNullException("email");

AddReplyTos(new List<EmailAddress> { email });
}

/// <summary>
/// Add reply-to recipients.
/// </summary>
/// <param name="emails">A list of reply-to recipients. Each email object within this array may contain the recipient’s name, but must always contain the recipient’s email.</param>
/// <exception cref="System.ArgumentNullException">Thrown when the emails parameter is null</exception>
/// <exception cref="System.InvalidOperationException">Thrown when the emails parameter is empty</exception>
public void AddReplyTos(List<EmailAddress> emails)
{
if (emails == null)
throw new ArgumentNullException("emails");
if (emails.Count == 0)
throw new InvalidOperationException("Sequence contains no elements");

if (ReplyTos == null) ReplyTos = new List<EmailAddress>();
ReplyTos.AddRange(emails);
}

/// <summary>
/// Add a substitution to the email.
/// You may not include more than 100 substitutions per personalization object, and the total collective size of your substitutions may not exceed 10,000 bytes per personalization object.
@@ -860,6 +910,63 @@ public void SetBypassListManagement(bool enable)
return;
}

/// <summary>
/// Set the bypass spam management setting.
/// Allows you to bypass the spam report list to ensure that the email is delivered to recipients. Bounce and unsubscribe lists will still be checked; addresses on these other lists will not receive the message.
/// </summary>
/// <param name="enable">Gets or sets a value indicating whether this setting is enabled.</param>
public void SetBypassSpamManagement(bool enable)
{
if (this.MailSettings == null)
{
this.MailSettings = new MailSettings();
}

this.MailSettings.BypassSpamManagement = new BypassSpamManagement
{
Enable = enable,
};
return;
}

/// <summary>
/// Set the bypass bounce management setting.
/// Allows you to bypass the bounce list to ensure that the email is delivered to recipients. Spam report and unsubscribe lists will still be checked; addresses on these other lists will not receive the message.
/// </summary>
/// <param name="enable">Gets or sets a value indicating whether this setting is enabled.</param>
public void SetBypassBounceManagement(bool enable)
{
if (this.MailSettings == null)
{
this.MailSettings = new MailSettings();
}

this.MailSettings.BypassBounceManagement = new BypassBounceManagement
{
Enable = enable,
};
return;
}

/// <summary>
/// Set the bypass unsubscribe management setting.
/// Allows you to bypass the global unsubscribe list to ensure that the email is delivered to recipients. Bounce and spam report lists will still be checked; addresses on these other lists will not receive the message. This filter applies only to global unsubscribes and will not bypass group unsubscribes.
/// </summary>
/// <param name="enable">Gets or sets a value indicating whether this setting is enabled.</param>
public void SetBypassUnsubscribeManagement(bool enable)
{
if (this.MailSettings == null)
{
this.MailSettings = new MailSettings();
}

this.MailSettings.BypassUnsubscribeManagement = new BypassUnsubscribeManagement
{
Enable = enable,
};
return;
}

/// <summary>
/// Set the footer setting.
/// The default footer that you would like appended to the bottom of every email.
2 changes: 1 addition & 1 deletion src/SendGrid/Permissions/ScopeOptions.cs
Original file line number Diff line number Diff line change
@@ -14,6 +14,6 @@ public enum ScopeOptions
/// <summary>
/// Read-only scopes. When fitlering scopes this will include only those that end with ".read"
/// </summary>
ReadOnly
ReadOnly
}
}
2 changes: 1 addition & 1 deletion src/SendGrid/Permissions/SendGridClientExtensions.cs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ public static class SendGridClientExtensions
public static async Task<SendGridPermissionsBuilder> CreateMaskedPermissionsBuilderForClient(this ISendGridClient client)
{
var response = await client.RequestAsync(method: SendGridClient.Method.GET, urlPath: "scopes");
var body = await response.DeserializeResponseBodyAsync(response.Body);
var body = await response.DeserializeResponseBodyAsync();
var userScopesJArray = (body["scopes"] as JArray);
var includedScopes = userScopesJArray.Values<string>().ToArray();
var builder = new SendGridPermissionsBuilder();
60 changes: 30 additions & 30 deletions src/SendGrid/Permissions/SendGridPermissionsBuilder.Scopes.cs
Original file line number Diff line number Diff line change
@@ -296,17 +296,17 @@ partial class SendGridPermissionsBuilder
#endregion
#region Mail
,{ SendGridPermission.Mail, new[]
{
{
"mail.batch.create",
"mail.batch.delete",
"mail.batch.read",
"mail.batch.update",
"mail.send"
}}
}}
#endregion
#region Mail Settings
,{ SendGridPermission.MailSettings, new[]
{
{
"mail_settings.address_whitelist.read",
"mail_settings.address_whitelist.update",
"mail_settings.bounce_purge.read",
@@ -319,56 +319,56 @@ partial class SendGridPermissionsBuilder
"mail_settings.forward_spam.update",
"mail_settings.template.read",
"mail_settings.template.update"
}}
}}
#endregion
#region Marketing Campaigns
,{ SendGridPermission.MarketingCampaigns, new[]
{
{
"marketing_campaigns.create",
"marketing_campaigns.delete",
"marketing_campaigns.read",
"marketing_campaigns.update"
}}
}}
#endregion
#region Newsletter
,{ SendGridPermission.Newsletter, new[]
{
{
"newsletter.create",
"newsletter.delete",
"newsletter.read",
"newsletter.update"
}}
}}
#endregion
#region PartnerSettings
,{ SendGridPermission.PartnerSettings, new[]
{
{
"partner_settings.new_relic.read",
"partner_settings.new_relic.update",
"partner_settings.read"
}}
}}
#endregion
#region Reverse DNS
,{ SendGridPermission.ReverseDNS, new[]
{
{
"access_settings.activity.read",
"access_settings.whitelist.create",
"access_settings.whitelist.delete",
"access_settings.whitelist.read",
"access_settings.whitelist.update"
}}
}}
#endregion
#region Scheduled Sends
,{ SendGridPermission.ScheduledSends, new[]
{
{
"user.scheduled_sends.create",
"user.scheduled_sends.delete",
"user.scheduled_sends.read",
"user.scheduled_sends.update"
}}
}}
#endregion
#region Stats
,{ SendGridPermission.Stats, new[]
{
{
"email_activity.read",
"stats.read",
"stats.global.read",
@@ -381,11 +381,11 @@ partial class SendGridPermissionsBuilder
"clients.stats.read",
"clients.tablet.stats.read",
"clients.webmail.stats.read"
}}
}}
#endregion
#region Subusers
,{ SendGridPermission.Subusers, new[]
{
{
"subusers.create",
"subusers.delete",
"subusers.read",
@@ -407,11 +407,11 @@ partial class SendGridPermissionsBuilder
"subusers.stats.monthly.read",
"subusers.stats.sums.read",
"subusers.summary.read"
}}
}}
#endregion
#region Suppressions
,{ SendGridPermission.Suppressions, new[]
{
{
"suppression.create",
"suppression.delete",
"suppression.read",
@@ -436,20 +436,20 @@ partial class SendGridPermissionsBuilder
"suppression.unsubscribes.read",
"suppression.unsubscribes.update",
"suppression.unsubscribes.delete"
}}
}}
#endregion
#region Teammates
,{ SendGridPermission.Teammates, new[]
{
{
"teammates.create",
"teammates.read",
"teammates.update",
"teammates.delete"
}}
}}
#endregion
#region Templates
,{ SendGridPermission.Templates, new[]
{
{
"templates.create",
"templates.delete",
"templates.read",
@@ -462,11 +462,11 @@ partial class SendGridPermissionsBuilder
"templates.versions.delete",
"templates.versions.read",
"templates.versions.update"
}}
}}
#endregion
#region Tracking
,{ SendGridPermission.Tracking, new[]
{
{
"tracking_settings.click.read",
"tracking_settings.click.update",
"tracking_settings.google_analytics.read",
@@ -476,11 +476,11 @@ partial class SendGridPermissionsBuilder
"tracking_settings.read",
"tracking_settings.subscription.read",
"tracking_settings.subscription.update"
}}
}}
#endregion
#region User Settings
,{ SendGridPermission.UserSettings, new[]
{
{
"user.account.read",
"user.credits.read",
"user.email.create",
@@ -501,11 +501,11 @@ partial class SendGridPermissionsBuilder
"user.timezone.update",
"user.username.read",
"user.username.update"
}}
}}
#endregion
#region Webhooks
,{ SendGridPermission.Webhook, new[]
{
{
"user.webhooks.event.settings.read",
"user.webhooks.event.settings.update",
"user.webhooks.event.test.create",
@@ -516,7 +516,7 @@ partial class SendGridPermissionsBuilder
"user.webhooks.parse.settings.read",
"user.webhooks.parse.settings.update",
"user.webhooks.parse.stats.read"
}}
}}
#endregion
};
}
28 changes: 23 additions & 5 deletions src/SendGrid/Reliability/ReliabilitySettings.cs
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@
// </copyright>

using System;
using System.Collections.Generic;
using System.Net;

namespace SendGrid.Helpers.Reliability
{
@@ -23,10 +25,10 @@ public ReliabilitySettings()
/// <summary>
/// Initializes a new instance of the <see cref="ReliabilitySettings"/> class.
/// </summary>
/// <param name="maximumNumberOfRetries">The maximum number of retries to execute against when sending an HTTP Request before throwing an exception.</param>
/// <param name="minimumBackoff">The minimum amount of time to wait between between HTTP retries.</param>
/// <param name="maximumBackOff">the maximum amount of time to wait between between HTTP retries.</param>
/// <param name="deltaBackOff">the value that will be used to calculate a random delta in the exponential delay between retries.</param>
/// <param name="maximumNumberOfRetries">The maximum number of retries to execute against when sending an HTTP Request before throwing an exception. Max value of 5. Default value of 0.</param>
/// <param name="minimumBackoff">The minimum amount of time to wait between between HTTP retries. Default value of 0 seconds.</param>
/// <param name="maximumBackOff" max="30 seconds">the maximum amount of time to wait between between HTTP retries. Max value of 30 seconds. Default value of 0 seconds.</param>
/// <param name="deltaBackOff">the value that will be used to calculate a random delta in the exponential delay between retries. Default value of 0 seconds.</param>
public ReliabilitySettings(int maximumNumberOfRetries, TimeSpan minimumBackoff, TimeSpan maximumBackOff, TimeSpan deltaBackOff)
{
if (maximumNumberOfRetries < 0)
@@ -89,5 +91,21 @@ public ReliabilitySettings(int maximumNumberOfRetries, TimeSpan minimumBackoff,
/// Gets the value that will be used to calculate a random delta in the exponential delay between retries. Defaults to 1 second.
/// </summary>
public TimeSpan DeltaBackOff { get; }

/// <summary>
/// Gets status codes for which request would be retied.
/// </summary>
public List<HttpStatusCode> RetriableServerErrorStatusCodes { get; } = new List<HttpStatusCode>(DefaultRetriableServerErrorStatusCodes);

/// <summary>
/// Gets default status codes for which request would be retied.
/// </summary>
public static List<HttpStatusCode> DefaultRetriableServerErrorStatusCodes { get; } = new List<HttpStatusCode>()
{
HttpStatusCode.InternalServerError,
HttpStatusCode.BadGateway,
HttpStatusCode.ServiceUnavailable,
HttpStatusCode.GatewayTimeout,
};
}
}
}
18 changes: 4 additions & 14 deletions src/SendGrid/Reliability/RetryDelegatingHandler.cs
Original file line number Diff line number Diff line change
@@ -4,8 +4,7 @@
// </copyright>

using System;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@@ -17,15 +16,6 @@ namespace SendGrid.Helpers.Reliability
/// </summary>
public class RetryDelegatingHandler : DelegatingHandler
{
private static readonly List<HttpStatusCode> RetriableServerErrorStatusCodes =
new List<HttpStatusCode>()
{
HttpStatusCode.InternalServerError,
HttpStatusCode.BadGateway,
HttpStatusCode.ServiceUnavailable,
HttpStatusCode.GatewayTimeout,
};

private readonly ReliabilitySettings settings;

/// <summary>
@@ -69,7 +59,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
{
responseMessage = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

ThrowHttpRequestExceptionIfResponseCodeCanBeRetried(responseMessage);
this.ThrowHttpRequestExceptionIfResponseCodeCanBeRetried(responseMessage);

sent = true;
}
@@ -101,9 +91,9 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
return responseMessage;
}

private static void ThrowHttpRequestExceptionIfResponseCodeCanBeRetried(HttpResponseMessage responseMessage)
private void ThrowHttpRequestExceptionIfResponseCodeCanBeRetried(HttpResponseMessage responseMessage)
{
if (RetriableServerErrorStatusCodes.Contains(responseMessage.StatusCode))
if (this.settings.RetriableServerErrorStatusCodes.Contains(responseMessage.StatusCode))
{
throw new HttpRequestException(string.Format("Http status code '{0}' indicates server error", responseMessage.StatusCode));
}
41 changes: 28 additions & 13 deletions src/SendGrid/Response.cs
Original file line number Diff line number Diff line change
@@ -21,17 +21,17 @@ public class Response
/// <summary>
/// The status code returned from Twilio SendGrid.
/// </summary>
private HttpStatusCode statusCode;
private HttpStatusCode _statusCode;

/// <summary>
/// The response body returned from Twilio SendGrid.
/// </summary>
private HttpContent body;
private HttpContent _body;

/// <summary>
/// The response headers returned from Twilio SendGrid.
/// </summary>
private HttpResponseHeaders headers;
private HttpResponseHeaders _headers;

/// <summary>
/// Initializes a new instance of the <see cref="Response"/> class.
@@ -53,12 +53,12 @@ public HttpStatusCode StatusCode
{
get
{
return this.statusCode;
return this._statusCode;
}

set
{
this.statusCode = value;
this._statusCode = value;
}
}

@@ -72,33 +72,35 @@ public bool IsSuccessStatusCode

/// <summary>
/// Gets or sets the response body returned from Twilio SendGrid.
/// <see href="https://docs.microsoft.com/dotnet/api/system.net.http.httpcontent"></see>
/// </summary>
public HttpContent Body
{
get
{
return this.body;
return this._body;
}

set
{
this.body = value;
this._body = value;
}
}

/// <summary>
/// Gets or sets the response headers returned from Twilio SendGrid.
/// <see href="https://docs.microsoft.com/dotnet/api/system.net.http.headers.httpresponseheaders"></see>
/// </summary>
public HttpResponseHeaders Headers
{
get
{
return this.headers;
return this._headers;
}

set
{
this.headers = value;
this._headers = value;
}
}

@@ -107,8 +109,14 @@ public HttpResponseHeaders Headers
/// </summary>
/// <param name="content">https://docs.microsoft.com/dotnet/api/system.net.http.httpcontent.</param>
/// <returns>Dictionary object representation of HttpContent.</returns>
public virtual async Task<Dictionary<string, dynamic>> DeserializeResponseBodyAsync(HttpContent content)
public virtual async Task<Dictionary<string, dynamic>> DeserializeResponseBodyAsync(HttpContent content = null)
{
content = content ?? this._body;
if (content is null)
{
return new Dictionary<string, dynamic>();
}

var stringContent = await content.ReadAsStringAsync().ConfigureAwait(false);
var dsContent = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(stringContent);
return dsContent;
@@ -117,12 +125,19 @@ public virtual async Task<Dictionary<string, dynamic>> DeserializeResponseBodyAs
/// <summary>
/// Converts string formatted response headers to a Dictionary.
/// </summary>
/// <param name="content">https://docs.microsoft.com/dotnet/api/system.net.http.headers.httpresponseheaders.</param>
/// <param name="headers">https://docs.microsoft.com/dotnet/api/system.net.http.headers.httpresponseheaders.</param>
/// <returns>Dictionary object representation of HttpResponseHeaders.</returns>
public virtual Dictionary<string, string> DeserializeResponseHeaders(HttpResponseHeaders content)
public virtual Dictionary<string, string> DeserializeResponseHeaders(HttpResponseHeaders headers = null)
{
var dsContent = new Dictionary<string, string>();
foreach (var pair in content)

headers = headers ?? this._headers;
if (headers == null)
{
return dsContent;
}

foreach (var pair in headers)
{
dsContent.Add(pair.Key, pair.Value.First());
}
6 changes: 3 additions & 3 deletions src/SendGrid/SendGrid.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<VersionPrefix>9.24.0</VersionPrefix>
<VersionPrefix>9.29.3</VersionPrefix>
<TargetFrameworks>netstandard1.3;netstandard2.0;net452;net40</TargetFrameworks>
<PlatformTarget>anycpu</PlatformTarget>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -45,8 +45,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" Condition=" '$(OS)' != 'Windows_NT' " />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="starkbank-ecdsa" Version="[1.3.1, 2.0.0)" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="starkbank-ecdsa" Version="[1.3.3, 2.0.0)" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
15 changes: 10 additions & 5 deletions src/SendGrid/SendGridClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;

@@ -20,9 +21,10 @@ public class SendGridClient : BaseClient
/// <param name="requestHeaders">A dictionary of request headers.</param>
/// <param name="version">API version, override AddVersion to customize.</param>
/// <param name="urlPath">Path to endpoint (e.g. /path/to/endpoint).</param>
/// <param name="httpErrorAsException">Indicates whether HTTP error responses should be raised as exceptions. Default is false.</param>
/// <returns>Interface to the Twilio SendGrid REST API.</returns>
public SendGridClient(IWebProxy webProxy, string apiKey, string host = null, Dictionary<string, string> requestHeaders = null, string version = null, string urlPath = null, bool httpErrorAsException = false)
: base(webProxy, buildOptions(apiKey, host, requestHeaders, version, urlPath))
: base(webProxy, buildOptions(apiKey, host, requestHeaders, version, urlPath, httpErrorAsException))
{
}

@@ -35,9 +37,10 @@ public SendGridClient(IWebProxy webProxy, string apiKey, string host = null, Dic
/// <param name="requestHeaders">A dictionary of request headers.</param>
/// <param name="version">API version, override AddVersion to customize.</param>
/// <param name="urlPath">Path to endpoint (e.g. /path/to/endpoint).</param>
/// <param name="httpErrorAsException">Indicates whether HTTP error responses should be raised as exceptions. Default is false.</param>
/// <returns>Interface to the Twilio SendGrid REST API.</returns>
public SendGridClient(HttpClient httpClient, string apiKey, string host = null, Dictionary<string, string> requestHeaders = null, string version = null, string urlPath = null, bool httpErrorAsException = false)
: base(httpClient, buildOptions(apiKey, host, requestHeaders, version, urlPath))
: base(httpClient, buildOptions(apiKey, host, requestHeaders, version, urlPath, httpErrorAsException))
{
}

@@ -51,7 +54,7 @@ public SendGridClient(HttpClient httpClient, string apiKey, string host = null,
/// <param name="urlPath">Path to endpoint (e.g. /path/to/endpoint).</param>
/// <returns>Interface to the Twilio SendGrid REST API.</returns>
public SendGridClient(string apiKey, string host = null, Dictionary<string, string> requestHeaders = null, string version = null, string urlPath = null)
: base(buildOptions(apiKey, host, requestHeaders, version, urlPath))
: base(buildOptions(apiKey, host, requestHeaders, version, urlPath, false))
{
}

@@ -76,7 +79,7 @@ public SendGridClient(HttpClient httpClient, SendGridClientOptions options)
{
}

private static SendGridClientOptions buildOptions(string apiKey, string host, Dictionary<string, string> requestHeaders, string version, string urlPath)
private static SendGridClientOptions buildOptions(string apiKey, string host, Dictionary<string, string> requestHeaders, string version, string urlPath, bool httpErrorAsException)
{
return new SendGridClientOptions
{
@@ -85,7 +88,9 @@ private static SendGridClientOptions buildOptions(string apiKey, string host, Di
RequestHeaders = requestHeaders ?? DefaultOptions.RequestHeaders,
Version = version ?? DefaultOptions.Version,
UrlPath = urlPath ?? DefaultOptions.UrlPath,
HttpErrorAsException = httpErrorAsException
};
}

}
}
31 changes: 31 additions & 0 deletions src/SendGrid/SendGridClientOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net.Http.Headers;

namespace SendGrid
@@ -8,6 +9,12 @@ namespace SendGrid
/// </summary>
public class SendGridClientOptions : BaseClientOptions
{
Dictionary<string, string> REGION_HOST_MAP = new Dictionary<string, string>
{
{"eu", "https://api.eu.sendgrid.com/"},
{"global", "https://api.sendgrid.com/"}
};

/// <summary>
/// Initializes a new instance of the <see cref="SendGridClientOptions"/> class.
/// </summary>
@@ -36,5 +43,29 @@ public string ApiKey
Auth = new AuthenticationHeaderValue("Bearer", apiKey);
}
}

/// <summary>
/// Sets the data residency for the SendGrid client.
/// </summary>
/// <param name="region">The desired data residency region ("global" or "eu").</param>
/// Global is the default residency (or region)
/// Global region means the message will be sent through https://api.sendgrid.com
/// EU region means the message will be sent through https://api.eu.sendgrid.com
/// <returns>The updated SendGridClientOptions instance.</returns>
public SendGridClientOptions SetDataResidency(string region)
{
if (string.IsNullOrWhiteSpace(region))
{
throw new ArgumentNullException(nameof(region));
}

if (!REGION_HOST_MAP.ContainsKey(region))
{
throw new InvalidOperationException("Region can only be 'global' or 'eu'.");
}
string result = REGION_HOST_MAP.ContainsKey(region) ? REGION_HOST_MAP[region] : "https://api.sendgrid.com";
Host = result;
return this;
}
}
}
200 changes: 194 additions & 6 deletions tests/SendGrid.Tests/Integration.cs

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions tests/SendGrid.Tests/LicenseTests.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace SendGrid.Tests
{
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Xunit;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Xunit;

public class LicenseTests
{
2 changes: 1 addition & 1 deletion tests/SendGrid.Tests/PermissionsBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -78,7 +78,7 @@ public void IncludeThrowsIfAnyScopeParamIsInvalid()
public void IncludeThrowsIfAnyScopeIsInvalid()
{
var sb = new SendGridPermissionsBuilder();
Assert.Throws<InvalidOperationException>(() => sb.Include(new [] {"alert.create", "bad.scope" }));
Assert.Throws<InvalidOperationException>(() => sb.Include(new[] { "alert.create", "bad.scope" }));
}

[Fact]
Original file line number Diff line number Diff line change
@@ -48,5 +48,19 @@ public void WithANullCarbonCopyThenAnExceptionIsThrown()
var sendGridMessage = MailHelper.CreateSingleEmail(new EmailAddress(), new EmailAddress(), string.Empty, string.Empty, string.Empty);
Assert.Throws<ArgumentNullException>(() => { sendGridMessage.AddCc(null, 0); });
}

[Fact]
public void WithAnEmptyListOfReplyTosThenAnExceptionIsThrown()
{
var sendGridMessage = MailHelper.CreateSingleEmail(new EmailAddress(), new EmailAddress(), string.Empty, string.Empty, string.Empty);
Assert.Throws<InvalidOperationException>(() => { sendGridMessage.AddReplyTos(new List<EmailAddress>()); });
}

[Fact]
public void WithANullListOfReplyTosThenAnExceptionIsThrown()
{
var sendGridMessage = MailHelper.CreateSingleEmail(new EmailAddress(), new EmailAddress(), string.Empty, string.Empty, string.Empty);
Assert.Throws<ArgumentNullException>(() => { sendGridMessage.AddReplyTos(null); });
}
}
}
5 changes: 3 additions & 2 deletions tests/SendGrid.Tests/Reliability/ReliabilitySettingsTests.cs
Original file line number Diff line number Diff line change
@@ -9,8 +9,8 @@ public class ReliabilitySettingsTests
[Fact]
public void ShouldNotAllowNegativeRetryCount()
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>
new ReliabilitySettings(-1,
var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>
new ReliabilitySettings(-1,
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1)));
@@ -99,6 +99,7 @@ public void ShouldPassValidValuesFromDefaultConstruct()
Assert.Equal(TimeSpan.Zero, defaultSettings.MinimumBackOff);
Assert.Equal(TimeSpan.Zero, defaultSettings.DeltaBackOff);
Assert.Equal(0, defaultSettings.MaximumNumberOfRetries);
Assert.Equal(ReliabilitySettings.DefaultRetriableServerErrorStatusCodes, defaultSettings.RetriableServerErrorStatusCodes);
}

[Fact]
20 changes: 2 additions & 18 deletions tests/SendGrid.Tests/RequiredFilesExistTest.cs
Original file line number Diff line number Diff line change
@@ -7,7 +7,8 @@ public class TestRequiredFilesExist
{

// ./Docker or docker/Docker
public void checkDockerExists() {
public void checkDockerExists()
{
bool dockerExists = File.Exists("./Dockerfile") ||
File.Exists("./docker/Dockerfile");
Assert.True(dockerExists);
@@ -33,17 +34,6 @@ public void checkGitIgnoreExists()
Assert.True(File.Exists("./.gitignore"));
}

// ./.travis.yml
public void checkTravisExists()
{
Assert.True(File.Exists("./.travis.yml"));
}

// ./.codeclimate.yml
public void checkCodeClimateExists()
{
Assert.True(File.Exists("./.codeclimate.yml"));
}

// ./CHANGELOG.md
public void checkChangelogExists()
@@ -63,12 +53,6 @@ public void checkContributingGuideExists()
Assert.True(File.Exists("./CONTRIBUTING.md"));
}

// ./ISSUE_TEMPLATE.md
public void checkIssuesTemplateExists()
{
Assert.True(File.Exists("./ISSUE_TEMPLATE.md"));
}

// ./LICENSE
public void checkLicenseExists()
{
68 changes: 68 additions & 0 deletions tests/SendGrid.Tests/ResponseTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Newtonsoft.Json.Linq;

using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

using Xunit;

namespace SendGrid.Tests
{
public class ResponseTests
{
[Fact]
public async Task DeserializeResponseBodyAsync_NullHttpContent_ReturnsEmptyDictionary()
{
var response = new Response(HttpStatusCode.OK, null, null);
Dictionary<string, dynamic> responseBody = await response.DeserializeResponseBodyAsync();
Assert.Empty(responseBody);
}

[Fact]
public async Task DeserializeResponseBodyAsync_JsonHttpContent_ReturnsBodyAsDictionary()
{
var content = "{\"scopes\": [\"alerts.read\"]}";
var response = new Response(HttpStatusCode.OK, new StringContent(content), null);
Dictionary<string, dynamic> responseBody = await response.DeserializeResponseBodyAsync();
Assert.Equal(new JArray() { "alerts.read" }, responseBody["scopes"]);
}

[Fact]
public async Task DeserializeResponseBodyAsync_OverrideHttpContent_ReturnsBodyAsDictionary()
{
var content = "{\"scopes\": [\"alerts.read\"]}";
var response = new Response(HttpStatusCode.OK, null, null);
Dictionary<string, dynamic> responseBody = await response.DeserializeResponseBodyAsync(new StringContent(content));
Assert.Equal(new JArray() { "alerts.read" }, responseBody["scopes"]);
}

[Fact]
public void DeserializeResponseHeaders_NullHttpResponseHeaders_ReturnsEmptyDictionary()
{
var response = new Response(HttpStatusCode.OK, null, null);
Dictionary<string, string> responseHeadersDeserialized = response.DeserializeResponseHeaders();
Assert.Empty(responseHeadersDeserialized);
}

[Fact]
public void DeserializeResponseHeaders_HttpResponseHeaders_ReturnsHeadersAsDictionary()
{
var message = new HttpResponseMessage();
message.Headers.Add("HeaderKey", "HeaderValue");
var response = new Response(HttpStatusCode.OK, null, message.Headers);
Dictionary<string, string> responseHeadersDeserialized = response.DeserializeResponseHeaders();
Assert.Equal("HeaderValue", responseHeadersDeserialized["HeaderKey"]);
}

[Fact]
public void DeserializeResponseHeaders_OverrideHttpResponseHeaders_ReturnsHeadersAsDictionary()
{
var message = new HttpResponseMessage();
message.Headers.Add("HeaderKey", "HeaderValue");
var response = new Response(HttpStatusCode.OK, null, null);
Dictionary<string, string> responseHeadersDeserialized = response.DeserializeResponseHeaders(message.Headers);
Assert.Equal("HeaderValue", responseHeadersDeserialized["HeaderKey"]);
}
}
}
55 changes: 55 additions & 0 deletions tests/SendGrid.Tests/SendgridEmailClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
namespace SendGrid.Tests
{
using System;
using System.Threading.Tasks;
using SendGrid.Helpers.Mail;
using Xunit;

public class SendgridEmailClientTests
{
[Fact]
public void TestClientOptionsConstruction()
{
var options = new SendGridClientOptions();
Assert.Equal("https://api.sendgrid.com", options.Host);
}
[Fact]
public void TestClientOptionsSetDataResidency()
{
var options = new SendGridClientOptions();
options.SetDataResidency("eu");
Assert.Equal("https://api.eu.sendgrid.com/", options.Host);
}
[Fact]
public void TestClientOptionsSetDataResidencyEU()
{
var options = new SendGridClientOptions();
options.SetDataResidency("eu");
Assert.Equal("https://api.eu.sendgrid.com/", options.Host);
}

[Fact]
public void TestClientOptionsSetViaSendgridClient()
{
var options = new SendGridClientOptions();
options.SetDataResidency("eu");
var sg = new SendGridClient(options);
Assert.Equal("https://api.eu.sendgrid.com/", options.Host);
}

[Fact]
public void TestErrorClientOptionsNUllEmpty()
{
var options = new SendGridClientOptions();
Assert.Throws<ArgumentNullException>(() => options.SetDataResidency(""));
Assert.Throws<ArgumentNullException>(() => options.SetDataResidency(null));
}

[Fact]
public void TestErrorClientOptions()
{
var options = new SendGridClientOptions();
Assert.Throws<InvalidOperationException>(() => options.SetDataResidency("foo"));
}
}
}