├── .config
└── dotnet-tools.json
├── .csharpierrc
├── .editorconfig
├── .gitattributes
├── .github
├── dependabot.yml
└── workflows
│ └── on-update.yml
├── .gitignore
├── AUTHORS.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── build
├── Program.cs
└── build.csproj
├── docker
├── Dockerfile
├── build_and_deploy.sh
└── readme.md
├── examples
├── BCC
│ ├── BCC.csproj
│ └── Program.cs
├── CC
│ ├── CC.csproj
│ └── Program.cs
├── SendInline
│ ├── Program.cs
│ └── SendInline.csproj
└── SendTemplate
│ ├── Order.cs
│ ├── Program.cs
│ └── SendTemplate.csproj
└── src
├── SparkPost.Acceptance
├── ClientSteps.cs
├── MessageEvents.feature
├── MessageEventsSteps.cs
├── Metrics.feature
├── MetricsSteps.cs
├── RecipientListSteps.cs
├── RecipientLists.feature
├── ResponseSteps.cs
├── SparkPost.Acceptance.csproj
├── Suppressions.feature
├── SuppressionsSteps.cs
├── TransmissionSteps.cs
├── Transmissions.feature
└── testtextfile.txt
├── SparkPost.Tests
├── CastAsExtensions.cs
├── ClientTests.cs
├── DataMapperTests.cs
├── FileTests.cs
├── ListMessageEventsResponseTests.cs
├── MessageEventsQueryTests.cs
├── MetricsQueryTests.cs
├── RelayWebhookTests.cs
├── RequestMethodFinderTests.cs
├── RequestMethods
│ ├── DeleteTests.cs
│ ├── GetTests.cs
│ ├── PostTests.cs
│ └── PutTests.cs
├── RequestSenders
│ └── RequestSenderTests.cs
├── SparkPost.Tests.csproj
├── SubaccountTest.cs
├── SuppressionTests.cs
├── TransmissionTests.cs
├── UserAgentTests.cs
├── Utilities
│ └── SnakeCaseTests.cs
└── WebhookTests.cs
├── SparkPost.sln
└── SparkPost
├── Address.cs
├── Attachment.cs
├── Attributes.cs
├── BounceCategory.cs
├── BounceClass.cs
├── BounceClassDetails.cs
├── BounceClassesDetails.cs
├── CcHandling.cs
├── Client.cs
├── Content.cs
├── CreateSendingDomainResponse.cs
├── CreateSubaccountResponse.cs
├── CreateTemplateResponse.cs
├── DataMapper.cs
├── Dkim.cs
├── Dns.cs
├── EmailValidationResponse.cs
├── Events.cs
├── File.cs
├── GetMetricsResourceResponse.cs
├── GetMetricsResponse.cs
├── GetSendingDomainResponse.cs
├── IClient.cs
├── IMessageEvents.cs
├── IMetrics.cs
├── IRecipientLists.cs
├── IRecipientValidation.cs
├── IRequestMethod.cs
├── ISendingDomains.cs
├── ISubaccounts.cs
├── ISuppressions.cs
├── ITemplates.cs
├── ITransmissions.cs
├── IValueMapper.cs
├── InboundDomain.cs
├── InboundDomainResponse.cs
├── InboundDomains.cs
├── InlineImage.cs
├── LeftRight.cs
├── ListInboundDomainResponse.cs
├── ListMessageEventsResponse.cs
├── ListRelayWebhookResponse.cs
├── ListSendingDomainResponse.cs
├── ListSubaccountResponse.cs
├── ListSuppressionResponse.cs
├── ListTransmissionResponse.cs
├── ListWebhookResponse.cs
├── MessageEvent.cs
├── MessageEventSampleResponse.cs
├── MessageEventType.cs
├── MessageEvents.cs
├── MessageEventsQuery.cs
├── Metrics.cs
├── MetricsField.cs
├── MetricsQuery.cs
├── MetricsResourceQuery.cs
├── Options.cs
├── PageLink.cs
├── Recipient.cs
├── RecipientList.cs
├── RecipientLists.cs
├── RecipientType.cs
├── RecipientValidation.cs
├── RelayWebhook.cs
├── RelayWebhooks.cs
├── Request.cs
├── RequestMethodFinder.cs
├── RequestMethods
├── Delete.cs
├── Get.cs
├── Post.cs
├── Put.cs
├── PutAndPostAreTheSame.cs
└── RequestMethod.cs
├── RequestSenders
└── RequestSender.cs
├── Response.cs
├── ResponseException.cs
├── RetrieveEmailValidationResponse.cs
├── RetrieveRecipientListsResponse.cs
├── RetrieveRelayWebhookResponse.cs
├── RetrieveTemplateResponse.cs
├── RetrieveTemplatesResponse.cs
├── RetrieveTransmissionResponse.cs
├── RetrieveWebhookResponse.cs
├── SendRecipientListsResponse.cs
├── SendTransmissionResponse.cs
├── SendingDomain.cs
├── SendingDomainStatus.cs
├── SendingDomains.cs
├── SparkPost.csproj
├── Subaccount.cs
├── SubaccountCreate.cs
├── SubaccountStatus.cs
├── SubaccountUpdate.cs
├── Subaccounts.cs
├── Suppression.cs
├── Suppressions.cs
├── SuppressionsQuery.cs
├── Template.cs
├── TemplateContent.cs
├── TemplateOptions.cs
├── Templates.cs
├── Transmission.cs
├── Transmissions.cs
├── UpdateRecipientListResponse.cs
├── UpdateSendingDomainResponse.cs
├── UpdateSubaccountResponse.cs
├── UpdateSuppressionResponse.cs
├── Utilities
├── Jsonification.cs
├── MailMessageMapping.cs
├── SnakeCase.cs
└── StringHelper.cs
├── ValueMappers
├── AnonymousValueMapper.cs
├── BooleanValueMapper.cs
├── DateTimeOffsetValueMapper.cs
├── DateTimeValueMapper.cs
├── EnumValueMapper.cs
├── EnumerableValueMapper.cs
├── MapASetOfItemsUsingToDictionary.cs
├── MapASingleItemUsingToDictionary.cs
├── StringObjectDictionaryValueMapper.cs
└── StringStringDictionaryValueMapper.cs
├── VerifySendingDomain.cs
├── VerifySendingDomainResponse.cs
├── VerifySendingDomainStatus.cs
├── Webhook.cs
└── Webhooks.cs
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "csharpier": {
6 | "version": "0.18.0",
7 | "commands": [
8 | "dotnet-csharpier"
9 | ]
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/.csharpierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 150,
3 | "preprocessorSymbolSets": ["", "DEBUG", "DEBUG,CODE_STYLE"]
4 | }
5 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Declare files that will always have CRLF line endings on checkout.
2 | * text eol=lf
3 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions" # search for actions - there are other options available
4 | directory: "/" # search in .github/workflows under root `/`
5 | schedule:
6 | interval: "weekly" # check for action update every week
7 |
--------------------------------------------------------------------------------
/.github/workflows/on-update.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Build and Test
3 |
4 | on: [push]
5 |
6 | jobs:
7 | build-and-run-tests:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 | - uses: actions/setup-dotnet@v4
12 | with:
13 | dotnet-version: 6.0.301
14 | - run: dotnet run -p build/build.csproj
15 | - uses: actions/upload-artifact@v4
16 | with:
17 | name: SparkPost.nupkg
18 | path: artifacts/*
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Visual Studio 2015 cache/options directory
25 | .vs/
26 | # Uncomment if you have tasks that create the project's static files in wwwroot
27 | #wwwroot/
28 |
29 | # MSTest test Results
30 | [Tt]est[Rr]esult*/
31 | [Bb]uild[Ll]og.*
32 |
33 | # NUNIT
34 | *.VisualState.xml
35 | TestResult.xml
36 |
37 | # Build Results of an ATL Project
38 | [Dd]ebugPS/
39 | [Rr]eleasePS/
40 | dlldata.c
41 |
42 | # DNX
43 | project.lock.json
44 | artifacts/
45 |
46 | *_i.c
47 | *_p.c
48 | *_i.h
49 | *.ilk
50 | *.meta
51 | *.obj
52 | *.pch
53 | *.pdb
54 | *.pgc
55 | *.pgd
56 | *.rsp
57 | *.sbr
58 | *.tlb
59 | *.tli
60 | *.tlh
61 | *.tmp
62 | *.tmp_proj
63 | *.log
64 | *.vspscc
65 | *.vssscc
66 | .builds
67 | *.pidb
68 | *.svclog
69 | *.scc
70 |
71 | # Chutzpah Test files
72 | _Chutzpah*
73 |
74 | # Visual C++ cache files
75 | ipch/
76 | *.aps
77 | *.ncb
78 | *.opendb
79 | *.opensdf
80 | *.sdf
81 | *.cachefile
82 |
83 | # Visual Studio profiler
84 | *.psess
85 | *.vsp
86 | *.vspx
87 | *.sap
88 |
89 | # TFS 2012 Local Workspace
90 | $tf/
91 |
92 | # Guidance Automation Toolkit
93 | *.gpState
94 |
95 | # ReSharper is a .NET coding add-in
96 | _ReSharper*/
97 | *.[Rr]e[Ss]harper
98 | *.DotSettings.user
99 |
100 | # JustCode is a .NET coding add-in
101 | .JustCode
102 |
103 | # TeamCity is a build add-in
104 | _TeamCity*
105 |
106 | # DotCover is a Code Coverage Tool
107 | *.dotCover
108 |
109 | # NCrunch
110 | _NCrunch_*
111 | .*crunch*.local.xml
112 | nCrunchTemp_*
113 |
114 | # MightyMoose
115 | *.mm.*
116 | AutoTest.Net/
117 |
118 | # Web workbench (sass)
119 | .sass-cache/
120 |
121 | # Installshield output folder
122 | [Ee]xpress/
123 |
124 | # DocProject is a documentation generator add-in
125 | DocProject/buildhelp/
126 | DocProject/Help/*.HxT
127 | DocProject/Help/*.HxC
128 | DocProject/Help/*.hhc
129 | DocProject/Help/*.hhk
130 | DocProject/Help/*.hhp
131 | DocProject/Help/Html2
132 | DocProject/Help/html
133 |
134 | # Click-Once directory
135 | publish/
136 |
137 | # Publish Web Output
138 | *.[Pp]ublish.xml
139 | *.azurePubxml
140 | # TODO: Comment the next line if you want to checkin your web deploy settings
141 | # but database connection strings (with potential passwords) will be unencrypted
142 | *.pubxml
143 | *.publishproj
144 |
145 | # NuGet Packages
146 | *.nupkg
147 | # The packages folder can be ignored because of Package Restore
148 | **/packages/*
149 | # except build/, which is used as an MSBuild target.
150 | !**/packages/build/
151 | # Uncomment if necessary however generally it will be regenerated when needed
152 | #!**/packages/repositories.config
153 | # NuGet v3's project.json files produces more ignoreable files
154 | *.nuget.props
155 | *.nuget.targets
156 |
157 | # Microsoft Azure Build Output
158 | csx/
159 | *.build.csdef
160 |
161 | # Microsoft Azure Emulator
162 | ecf/
163 | rcf/
164 |
165 | # Microsoft Azure ApplicationInsights config file
166 | ApplicationInsights.config
167 |
168 | # Windows Store app package directory
169 | AppPackages/
170 | BundleArtifacts/
171 |
172 | # Visual Studio cache files
173 | # files ending in .cache can be ignored
174 | *.[Cc]ache
175 | # but keep track of directories ending in .cache
176 | !*.[Cc]ache/
177 |
178 | # Others
179 | ClientBin/
180 | ~$*
181 | *~
182 | *.dbmdl
183 | *.dbproj.schemaview
184 | *.pfx
185 | *.publishsettings
186 | node_modules/
187 | orleans.codegen.cs
188 |
189 | # RIA/Silverlight projects
190 | Generated_Code/
191 |
192 | # Backup & report files from converting an old project file
193 | # to a newer Visual Studio version. Backup files are not needed,
194 | # because we have git ;-)
195 | _UpgradeReport_Files/
196 | Backup*/
197 | UpgradeLog*.XML
198 | UpgradeLog*.htm
199 |
200 | # SQL Server files
201 | *.mdf
202 | *.ldf
203 |
204 | # Business Intelligence projects
205 | *.rdl.data
206 | *.bim.layout
207 | *.bim_*.settings
208 |
209 | # Microsoft Fakes
210 | FakesAssemblies/
211 |
212 | # GhostDoc plugin setting file
213 | *.GhostDoc.xml
214 |
215 | # Node.js Tools for Visual Studio
216 | .ntvs_analysis.dat
217 |
218 | # Visual Studio 6 build log
219 | *.plg
220 |
221 | # Visual Studio 6 workspace options file
222 | *.opt
223 |
224 | # Visual Studio LightSwitch build output
225 | **/*.HTMLClient/GeneratedArtifacts
226 | **/*.DesktopClient/GeneratedArtifacts
227 | **/*.DesktopClient/ModelManifest.xml
228 | **/*.Server/GeneratedArtifacts
229 | **/*.Server/ModelManifest.xml
230 | _Pvt_Extensions
231 |
232 | # Paket dependency manager
233 | .paket/paket.exe
234 |
235 | # FAKE - F# Make
236 | .fake/
237 | .DS_Store
238 | **/.idea/
239 | *.feature.cs
240 |
--------------------------------------------------------------------------------
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | ## Core contributors
2 |
3 | * Darren Cauthon (http://github.com/darrencauthon)
4 | * Stefan de Vogelaere (http://githun.com/stefandevo) - Xamarin Support
5 | * Geoffrey Ballenden (http://githun.com/ZA1)
6 | * Kiril Sidun (https://github.com/kirilsi)
7 | * Adam Hathcock (https://github.com/adamhathcock)
8 | * Combeenation (https://github.com/Combeenation)
9 | * ADD YOURSELF HERE (and link to your github page)
10 |
11 | ## Patches and suggestions
12 |
13 | * Chris Charabaruk (https://github.com/coldacid) - SPEQit
14 | * ADD YOURSELF HERE (and link to your github page)
15 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | This project adheres to [Semantic Versioning](http://semver.org/).
3 |
4 | All releases with documentation are posted to the Github Releases page:
5 |
6 | https://github.com/SparkPost/csharp-sparkpost/releases
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to csharp-sparkpost
2 |
3 | The following is a set of guidelines for contributing to csharp-sparkpost,
4 | which is hosted by [Darren Cauthon](https://github.com/darrencauthon) on GitHub.
5 | These are just guidelines, not rules, use your best judgment and feel free to
6 | propose changes to this document in a pull request.
7 |
8 | ## Submitting Issues
9 |
10 | * Before logging an issue, please [search existing issues](https://github.com/darrencauthon/csharp-sparkpost/issues?q=is%3Aissue+is%3Aopen) first.
11 |
12 | * You can create an issue [here](https://github.com/darrencauthon/csharp-sparkpost/issues/new). Please include the library version number and as much detail as possible in your report.
13 |
14 | ## Local Development
15 |
16 | 1. Fork this repo
17 | 1. Clone your fork
18 | 1. Write some code!
19 | 1. Please follow the pull request submission steps in the next section
20 |
21 | ## Contribution Steps
22 |
23 | To contribute to csharp-sparkpost:
24 |
25 | 1. Create a new branch named after the issue you’ll be fixing (include the issue number as the branch name, example: Issue in GH is #8 then the branch name should be ISSUE-8))
26 | 1. Write corresponding tests and code (only what is needed to satisfy the issue and tests please)
27 | * Include your tests in the 'test' directory in an appropriate test file
28 | * Write code to satisfy the tests
29 | 1. Ensure automated tests pass
30 | 1. Submit a new Pull Request applying your feature/fix branch to the `master` branch
31 |
32 | ### Releasing
33 |
34 | TODO: add instructions for publishing to https://www.nuget.org/
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C# Library for [SparkPost](https://www.sparkpost.com)
2 |
3 | A C# package for the [SparkPost API](https://developers.sparkpost.com/api). Xamarin.iOS and Xamarin.Android support provided in the Portable Package (PCL Profile7).
4 |
5 | ## Installation
6 |
7 | To install via NuGet, run the following command in the [Package Manager Console](http://docs.nuget.org/consume/package-manager-console):
8 |
9 | ```
10 | PM> Install-Package SparkPost
11 | ```
12 |
13 | Alternatively, you can get the latest dll from the releases tab. You can also download this code and compile it yourself.
14 |
15 | ## Usage
16 |
17 | #### Special Note about ```Async```
18 |
19 | By default, this library uses .Net 4.5's ```Async``` functionality for better performance ([read more here](https://msdn.microsoft.com/en-us/library/hh191443.aspx)). This requires knowledge and execution
20 | of the async/await behavior in C#. If you're noticing what seems to be weird behavior, or MVC action hangs,
21 | or anything of that nature, just switch your client to ```Sync``` and you'll get the expected (but blocking) behavior.
22 |
23 | ```c#
24 | client.CustomSettings.SendingMode = SendingModes.Sync;
25 | client.Transmissions.Send(transmission); // now this call will be made synchronously
26 |
27 | client.CustomSettings.SendingMode = SendingModes.Async;
28 | client.Transmissions.Send(transmission); // now this call will be made asynchronously
29 | ```
30 |
31 |
32 |
33 | ### Transmissions
34 |
35 | To send an email:
36 |
37 | ```c#
38 | var transmission = new Transmission();
39 | transmission.Content.From.Email = "testing@sparkpostbox.com";
40 | transmission.Content.Subject = "Oh hey!";
41 | transmission.Content.Text = "Testing SparkPost - the world\'s most awesomest email service!";
42 | transmission.Content.Html = "
Testing SparkPost - the world\'s most awesomest email service!
";
43 |
44 | var recipient = new Recipient
45 | {
46 | Address = new Address { Email = "my@email.com" }
47 | };
48 | transmission.Recipients.Add(recipient);
49 |
50 | var client = new Client("");
51 | client.Transmissions.Send(transmission);
52 | // or client.Transmissions.Send(transmission).Wait();
53 |
54 | ```
55 |
56 | To send a template email:
57 |
58 | ```c#
59 | var transmission = new Transmission();
60 | transmission.Content.TemplateId = "my-template-id";
61 | transmission.Content.From.Email = "testing@sparkpostbox.com";
62 |
63 | transmission.SubstitutionData["first_name"] = "John";
64 | transmission.SubstitutionData["last_name"] = "Doe";
65 |
66 | var orders = new List
67 | {
68 | new Order { OrderId = "1", Total = 101 },
69 | new Order { OrderId = "2", Total = 304 }
70 | };
71 |
72 | // you can pass more complicated data, so long as it
73 | // can be parsed easily to JSON
74 | transmission.SubstitutionData["orders"] = orders;
75 |
76 | var recipient = new Recipient
77 | {
78 | Address = new Address { Email = "my@email.com" }
79 | };
80 | transmission.Recipients.Add(recipient);
81 |
82 | var client = new Client("MY_API_KEY");
83 | client.Transmissions.Send(transmission);
84 | // or client.Transmissions.Send(transmission).Wait();
85 |
86 | ```
87 |
88 | ### Sub Accounts
89 |
90 | You can use the client to send emails through a sub account by passing the ```subAccountId``` to your client.
91 |
92 | ```c#
93 | client = new Client(YOUR_API_KEY, YOUR_SUB_ACCOUNT_ID);
94 | // now the emails will be processed through your sub account
95 | ```
96 |
97 | ### Suppression List
98 |
99 | The suppression list are users who have opted-out of your emails. To retrieve this list:
100 |
101 | ```c#
102 | var client = new Client("MY_API_KEY");
103 |
104 | client.Suppressions.List(); // returns a list of
105 |
106 | client.Suppressions.List(new { limit = 3 }); // it accepts an anonymous type for filters
107 |
108 | client.Suppressions.List(new SuppressionQuery()); // a SuppressionQuery is also allowed for typed help
109 | ```
110 |
111 | To add email addresses to the list:
112 |
113 | ```c#
114 | var client = new Client("MY_API_KEY");
115 |
116 | var item1 = new Suppression { Email = "testing@testing.com", NonTransactional = true };
117 | var item2 = new Suppression { Email = "testing2@testing.com", Description = "testing" };
118 |
119 | client.Suppressions.CreateOrUpdate(new []{ item1, item2 });
120 | ```
121 |
122 | To delete email addresses from the list:
123 |
124 | ```c#
125 | var client = new Client("MY_API_KEY");
126 |
127 | client.Suppressions.Delete("testing@testing.com");
128 | ```
129 |
130 | To retrieve details about an email address on (or not on) the list:
131 |
132 | ```c#
133 | var client = new Client("MY_API_KEY");
134 |
135 | client.Suppressions.Retrieve("testing@testing.com");
136 | ```
137 |
138 | ### Setting the API hostname
139 | ```c#
140 | var client = new Client("MY_API_KEY", "https://api.eu.sparkpost.com");
141 | ```
142 |
143 | ### Contribute
144 |
145 | We welcome your contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to help out.
146 |
147 | ### Change Log
148 |
149 | [See ChangeLog here](CHANGELOG.md)
150 |
--------------------------------------------------------------------------------
/build/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 | using GlobExpressions;
6 | using static Bullseye.Targets;
7 | using static SimpleExec.Command;
8 |
9 | const string Clean = "clean";
10 | const string Format = "format";
11 | const string Build = "build";
12 | const string Test = "test";
13 | const string Publish = "publish";
14 |
15 | Target(
16 | Clean,
17 | ForEach("**/bin", "**/obj"),
18 | dir =>
19 | {
20 | IEnumerable GetDirectories(string d)
21 | {
22 | return Glob.Directories(".", d);
23 | }
24 |
25 | void RemoveDirectory(string d)
26 | {
27 | if (Directory.Exists(d))
28 | {
29 | Console.WriteLine(d);
30 | Directory.Delete(d, true);
31 | }
32 | }
33 |
34 | foreach (var d in GetDirectories(dir))
35 | {
36 | RemoveDirectory(d);
37 | }
38 | }
39 | );
40 |
41 | Target(
42 | Format,
43 | () =>
44 | {
45 | Run("dotnet", "tool restore", ".");
46 | Run("dotnet", "csharpier --check .", ".");
47 | }
48 | );
49 |
50 | Target(
51 | Build,
52 | DependsOn(Format),
53 | () =>
54 | {
55 | Run("dotnet", "build src/SparkPost.sln -c Release");
56 | }
57 | );
58 |
59 | Target(
60 | Test,
61 | DependsOn(Build),
62 | () =>
63 | {
64 | Run("dotnet", "test src/SparkPost.sln");
65 | }
66 | );
67 |
68 | Target(
69 | Publish,
70 | DependsOn(Test),
71 | () =>
72 | {
73 | Run("dotnet", "pack src/SparkPost/SparkPost.csproj -c Release -o artifacts/");
74 | }
75 | );
76 |
77 | Target("default", DependsOn(Publish), () => Console.WriteLine("Done!"));
78 |
79 | await RunTargetsAndExitAsync(args);
80 |
--------------------------------------------------------------------------------
/build/build.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mono
2 | MAINTAINER Darren Cauthon
3 |
4 | RUN apt-get update
5 | RUN apt-get install -y wget git dos2unix vim zip
6 |
7 | RUN nuget update -self
8 |
9 | ENV MONO_THREADS_PER_CPU 2000
10 |
11 | WORKDIR /
12 |
13 | RUN git clone https://github.com/SparkPost/csharp-sparkpost.git
14 |
15 | WORKDIR /csharp-sparkpost/src
16 |
17 | ADD build_and_deploy.sh /csharp-sparkpost/src
18 | RUN chmod 777 build_and_deploy.sh
19 | RUN dos2unix build_and_deploy.sh
20 |
21 | CMD /csharp-sparkpost/src/build_and_deploy.sh
22 |
--------------------------------------------------------------------------------
/docker/build_and_deploy.sh:
--------------------------------------------------------------------------------
1 | git pull origin master
2 |
3 | nuget restore
4 | xbuild /p:Configuration=Release
5 |
6 | nuget pack SparkPost/SparkPost.nuspec -Prop Configuration=Release
7 |
8 | PACKAGE=$(ls *.nupkg)
9 |
10 | # This will unzip the nupkg, then zip it back up.
11 | # This is done to some issue with the nuget command
12 | # line app creating nupkg files that cannot be
13 | # used by Visual Studio.
14 | # https://github.com/NuGet/Home/issues/2833
15 | mv $PACKAGE file.zip
16 | mkdir stuff
17 | cd stuff
18 | unzip ../file.zip
19 | rm ../file.zip
20 | zip -r ../file.zip *
21 | cd ..
22 | mv file.zip $PACKAGE
23 |
24 | nuget push $PACKAGE $APIKEY -s nuget.org
25 |
--------------------------------------------------------------------------------
/docker/readme.md:
--------------------------------------------------------------------------------
1 | ## Build & Deploy via Docker & Nuget
2 |
3 | This docker container will pull the latest version of this library, create a nuget package, and deploy it to Nuget.
4 |
5 | The only thing is needs is a valid Nuget API key, from someone that has rights to publish the package to Nuget.
6 |
7 | ```
8 | cd docker
9 | docker build . # this will produce a hash key, say 12345678
10 | docker run -e "APIKEY=your_nuget_key_here" 12345678
11 | ```
12 |
13 | This container has been registered on Docker Hub, and can be run like so:
14 |
15 | ```
16 | docker run -e "APIKEY=your_nuget_key_here" darrencauthon/csharp-sparkpost
17 | ```
18 |
--------------------------------------------------------------------------------
/examples/BCC/BCC.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | Exe
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/BCC/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SparkPost;
3 |
4 | var apikey = "YOUR_API_KEY";
5 | var fromAddr = "from-csharp@yourdomain.com";
6 | var toAddr = "to@you.com";
7 | var ccAddr = "cc@them.com";
8 | var bccAddr = "bcc@sneaky.com";
9 |
10 | var trans = new Transmission();
11 |
12 | var to = new Recipient { Address = new Address { Email = toAddr } };
13 | trans.Recipients.Add(to);
14 |
15 | var cc = new Recipient
16 | {
17 | Address = new Address { Email = ccAddr, HeaderTo = toAddr }
18 | };
19 | trans.Recipients.Add(cc);
20 |
21 | var bcc = new Recipient
22 | {
23 | Address = new Address { Email = bccAddr, HeaderTo = toAddr }
24 | };
25 | trans.Recipients.Add(bcc);
26 |
27 | trans.Content.From.Email = fromAddr;
28 | trans.Content.Subject = "SparkPost BCC / CC example";
29 | trans.Content.Text = "This message was sent To 1 recipient, 1 recipient was CC'd and 1 sneaky recipient was BCC'd.";
30 | trans.Content.Headers.Add("CC", ccAddr);
31 |
32 | Console.Write("Sending BCC / CC sample mail...");
33 |
34 | var client = new Client(apikey);
35 |
36 | var response = await client.Transmissions.Send(trans);
37 |
38 | Console.WriteLine("done");
39 |
--------------------------------------------------------------------------------
/examples/CC/CC.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | Exe
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/CC/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SparkPost;
3 |
4 | var apikey = "YOUR_API_KEY";
5 | var fromAddr = "from-csharp@yourdomain.com";
6 | var toAddr = "to@you.com";
7 | var ccAddr = "cc@them.com";
8 |
9 | var trans = new Transmission();
10 |
11 | var to = new Recipient { Address = new Address { Email = toAddr } };
12 | trans.Recipients.Add(to);
13 |
14 | var cc = new Recipient
15 | {
16 | Address = new Address { Email = ccAddr, HeaderTo = toAddr }
17 | };
18 | trans.Recipients.Add(cc);
19 |
20 | trans.Content.From.Email = fromAddr;
21 | trans.Content.Subject = "SparkPost CC example";
22 | trans.Content.Text = "This message was sent To 1 recipient and 1 recipient was CC'd.";
23 | trans.Content.Headers.Add("CC", ccAddr);
24 |
25 | Console.Write("Sending CC sample mail...");
26 |
27 | var client = new Client(apikey);
28 |
29 | var response = await client.Transmissions.Send(trans);
30 |
31 | Console.WriteLine("done");
32 |
--------------------------------------------------------------------------------
/examples/SendInline/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using SparkPost;
4 |
5 | var apikey = "YOUR_API_KEY";
6 | var fromAddr = "from-csharp@yourdomain.com";
7 | var toAddr = "to@you.com";
8 |
9 | var trans = new Transmission();
10 |
11 | var to = new Recipient
12 | {
13 | Address = new Address { Email = toAddr },
14 | SubstitutionData = new Dictionary { { "firstName", "Jane" } }
15 | };
16 |
17 | trans.Recipients.Add(to);
18 |
19 | trans.SubstitutionData["firstName"] = "Oh Ye Of Little Name";
20 |
21 | trans.Content.From.Email = fromAddr;
22 | trans.Content.Subject = "SparkPost online content example";
23 | trans.Content.Text = "Greetings {{firstName or 'recipient'}}\nHello from C# land.";
24 | trans.Content.Html = "Greetings {{firstName or 'recipient'}}
Hello from C# land.
";
25 |
26 | Console.Write("Sending mail...");
27 |
28 | var client = new Client(apikey);
29 |
30 | var response = await client.Transmissions.Send(trans);
31 |
32 | Console.WriteLine("done");
33 |
--------------------------------------------------------------------------------
/examples/SendInline/SendInline.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | Exe
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/SendTemplate/Order.cs:
--------------------------------------------------------------------------------
1 | namespace SendTemplate;
2 |
3 | public record Order(int OrderId, string Desc, int Total);
4 |
--------------------------------------------------------------------------------
/examples/SendTemplate/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using SendTemplate;
4 | using SparkPost;
5 |
6 | var fromAddr = "from-csharp@yourdomain.com";
7 | var toAddr = "to@you.com";
8 | var apikey = "YOUR_API_KEY";
9 |
10 | var trans = new Transmission();
11 |
12 | var to = new Recipient
13 | {
14 | Address = new Address { Email = toAddr },
15 | SubstitutionData = new Dictionary { { "firstName", "Jane" } }
16 | };
17 |
18 | trans.Recipients.Add(to);
19 | trans.SubstitutionData["title"] = "Dr";
20 | trans.SubstitutionData["firstName"] = "Rick";
21 | trans.SubstitutionData["lastName"] = "Sanchez";
22 | trans.SubstitutionData["orders"] = new List { new(101, "Tomatoes", 5), new(271, "Entropy", 314) };
23 |
24 | trans.Content.From.Email = fromAddr;
25 | trans.Content.TemplateId = "orderSummary";
26 |
27 | Console.Write("Sending mail...");
28 |
29 | var client = new Client(apikey);
30 |
31 | var response = await client.Transmissions.Send(trans);
32 |
33 | Console.WriteLine("done");
34 |
--------------------------------------------------------------------------------
/examples/SendTemplate/SendTemplate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | Exe
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/ClientSteps.cs:
--------------------------------------------------------------------------------
1 | using TechTalk.SpecFlow;
2 |
3 | namespace SparkPost.Acceptance
4 | {
5 | [Binding]
6 | public class ClientSteps
7 | {
8 | private readonly ScenarioContext _scenarioContext;
9 |
10 | public ClientSteps(ScenarioContext scenarioContext)
11 | {
12 | _scenarioContext = scenarioContext;
13 | }
14 |
15 | [Given(@"my api key is '(.*)'")]
16 | public void GivenMyApiKeyIs(string apiKey)
17 | {
18 | var client = new Client(apiKey);
19 | _scenarioContext.Set(client);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/MessageEvents.feature:
--------------------------------------------------------------------------------
1 | Feature: Message Events
2 |
3 | Background:
4 | Given my api key is 'yyy'
5 |
6 | @ignore
7 | Scenario: Samples
8 | When I ask for samples of 'bounce'
9 | Then it should return a 200
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/MessageEventsSteps.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using TechTalk.SpecFlow;
3 |
4 | namespace SparkPost.Acceptance
5 | {
6 | [Binding]
7 | public class MessageEventsSteps
8 | {
9 | private readonly ScenarioContext _scenarioContext;
10 |
11 | public MessageEventsSteps(ScenarioContext scenarioContext)
12 | {
13 | _scenarioContext = scenarioContext;
14 | }
15 |
16 | [When(@"I ask for samples of '(.*)'")]
17 | public async Task WhenIAskForSamplesOf(string events)
18 | {
19 | var client = _scenarioContext.Get();
20 |
21 | MessageEventSampleResponse response = await client.MessageEvents.SamplesOf(events);
22 |
23 | _scenarioContext.Set(response);
24 | _scenarioContext.Set(response);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/Metrics.feature:
--------------------------------------------------------------------------------
1 | Feature: Metrics
2 |
3 | Background:
4 | Given my api key is 'yyy'
5 |
6 | @ignore
7 | Scenario: Checking for count accepted
8 | When I query my deliverability for count_accepted
9 | Then it should return a 200
10 | And it should return some metrics count
11 | @ignore
12 | Scenario: Bounce reasons
13 | When I query my bounce reasons
14 | Then it should return a 200
15 | And it should return some metrics count
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/MetricsSteps.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using TechTalk.SpecFlow;
4 | using Xunit;
5 |
6 | namespace SparkPost.Acceptance
7 | {
8 | [Binding]
9 | public class MetricsSteps
10 | {
11 | private readonly ScenarioContext _scenarioContext;
12 |
13 | public MetricsSteps(ScenarioContext scenarioContext)
14 | {
15 | _scenarioContext = scenarioContext;
16 | }
17 |
18 | [When(@"I query my deliverability for (.*)")]
19 | public async Task WhenIQueryMyDeliverability(string metric)
20 | {
21 | var client = _scenarioContext.Get();
22 | Response response = await client.Metrics.GetDeliverability(new { from = DateTime.MinValue, metrics = metric });
23 |
24 | _scenarioContext.Set(response);
25 | }
26 |
27 | [When(@"I query my bounce reasons")]
28 | public async Task y()
29 | {
30 | var client = _scenarioContext.Get();
31 | Response response = await client.Metrics.GetBounceReasons(new { from = DateTime.MinValue });
32 |
33 | _scenarioContext.Set(response);
34 | }
35 |
36 | [Then("it should return some metrics count")]
37 | public void x()
38 | {
39 | var response = _scenarioContext.Get();
40 | Assert.IsType(response);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/RecipientListSteps.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using TechTalk.SpecFlow;
5 | using TechTalk.SpecFlow.Assist;
6 |
7 | namespace SparkPost.Acceptance
8 | {
9 | [Binding]
10 | public class RecipientListSteps
11 | {
12 | private readonly ScenarioContext scenarioContext;
13 |
14 | public RecipientListSteps(ScenarioContext scenarioContext)
15 | {
16 | this.scenarioContext = scenarioContext;
17 | }
18 |
19 | [Given(@"I have a new recipient list as")]
20 | public void GivenIHaveANewRecipientListAs(Table table)
21 | {
22 | var recipientList = table.CreateInstance();
23 | scenarioContext.Set(recipientList);
24 | }
25 |
26 | [Given(@"I add '(.*)' to the recipient list")]
27 | public void GivenIAddToTheRecipientList(string email)
28 | {
29 | var recipientList = scenarioContext.Get();
30 | recipientList.Recipients.Add(new Recipient { Address = new Address { Email = email } });
31 | }
32 |
33 | [Given(@"I clear the recipients on the recipient list")]
34 | public void x()
35 | {
36 | var recipientList = scenarioContext.Get();
37 | recipientList.Recipients.Clear();
38 | }
39 |
40 | [Given(@"I do not have a recipient list of id '(.*)'")]
41 | public void GivenIDoNotHaveARecipientListOfId(string id)
42 | {
43 | var client = scenarioContext.Get();
44 | client.RecipientLists.Delete(id);
45 | }
46 |
47 | [When(@"I create the recipient list")]
48 | public async Task WhenICreateTheRecipientList()
49 | {
50 | var recipientList = scenarioContext.Get();
51 |
52 | var client = scenarioContext.Get();
53 |
54 | SendRecipientListsResponse response = await client.RecipientLists.Create(recipientList);
55 |
56 | scenarioContext.Set(response);
57 | scenarioContext.Set(response);
58 | }
59 |
60 | [When(@"I retrieve the ""(.*)"" recipient list")]
61 | public async Task WhenIRetrieveTheRecipientList(string key)
62 | {
63 | var client = scenarioContext.Get();
64 |
65 | RetrieveRecipientListsResponse response = await client.RecipientLists.Retrieve(key);
66 |
67 | scenarioContext.Set(response.RecipientList);
68 | }
69 |
70 | [When(@"I update the recipient list")]
71 | public async Task WhenIUpdateTheRecipientList()
72 | {
73 | var recipientList = scenarioContext.Get();
74 |
75 | var client = scenarioContext.Get();
76 |
77 | UpdateRecipientListResponse response = await client.RecipientLists.Update(recipientList);
78 |
79 | scenarioContext.Set(response);
80 | }
81 |
82 | [Then(@"it should have the following recipient list values")]
83 | public void ThenItShouldHaveTheFollowingRecipientListValues(Table table)
84 | {
85 | var recipientList = scenarioContext.Get();
86 | table.CompareToInstance(recipientList);
87 | }
88 |
89 | [Then(@"it should have the following recipients")]
90 | public void ThenItShouldHaveTheFollowingRecipients(Table table)
91 | {
92 | var recipientLists = scenarioContext.Get().Recipients.Select(x => new { x.Address.Email });
93 | table.CompareToSet(recipientLists);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/RecipientLists.feature:
--------------------------------------------------------------------------------
1 | Feature: Recipient Lists
2 |
3 | Background:
4 | Given my api key is 'yyy'
5 |
6 | @ignore
7 | Scenario: Retrieving a recipient list
8 | Given I do not have a recipient list of id 'test-name'
9 | And I have a new recipient list as
10 | | Id | Name | Description |
11 | | test-name | Test Name | Test Description |
12 | And I add 'test@test.com' to the recipient list
13 | And I add 'test2@test.com' to the recipient list
14 | When I create the recipient list
15 | When I retrieve the "test-name" recipient list
16 | Then it should return a 200
17 | And it should have the following recipients
18 | | Email |
19 | | test@test.com |
20 | | test2@test.com |
21 | And it should have the following recipient list values
22 | | Id | Name | Description |
23 | | test-name | Test Name | Test Description |
24 |
25 | @ignore
26 | Scenario: Creating a recipient list
27 | Given I do not have a recipient list of id 'test-name'
28 | And I have a new recipient list as
29 | | Id | Name | Description |
30 | | test-name | Test Name | Test Description |
31 | And I add 'test@test.com' to the recipient list
32 | When I create the recipient list
33 | Then it should return a 200
34 | When I retrieve the "test-name" recipient list
35 | Then it should have the following recipients
36 | | Email |
37 | | test@test.com |
38 |
39 | @ignore
40 | Scenario: Updating a recipient list
41 | Given I do not have a recipient list of id 'test-name'
42 | And I have a new recipient list as
43 | | Id | Name | Description |
44 | | test-name | Test Name | Test Description |
45 | And I add 'test@test.com' to the recipient list
46 | And I add 'test2@test.com' to the recipient list
47 | When I create the recipient list
48 | Given I have a new recipient list as
49 | | Id | Name | Description |
50 | | test-name | Test Name Again | Test Description Second |
51 | And I clear the recipients on the recipient list
52 | And I add 'test1@test.com' to the recipient list
53 | And I add 'test3@test.com' to the recipient list
54 | When I update the recipient list
55 | Then it should return a 200
56 | When I retrieve the "test-name" recipient list
57 | Then it should return a 200
58 | And it should have the following recipient list values
59 | | Id | Name | Description |
60 | | test-name | Test Name Again | Test Description Second |
61 | And it should have the following recipients
62 | | Email |
63 | | test1@test.com |
64 | | test3@test.com |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/ResponseSteps.cs:
--------------------------------------------------------------------------------
1 | using TechTalk.SpecFlow;
2 | using Xunit;
3 |
4 | namespace SparkPost.Acceptance
5 | {
6 | [Binding]
7 | public class ResponseSteps
8 | {
9 | private readonly ScenarioContext _scenarioContext;
10 |
11 | public ResponseSteps(ScenarioContext scenarioContext)
12 | {
13 | _scenarioContext = scenarioContext;
14 | }
15 |
16 | [Then(@"it should return a (.*)")]
17 | public void ThenItShouldReturnA(int statusCode)
18 | {
19 | var response = _scenarioContext.Get();
20 | Assert.Equal(statusCode, response.StatusCode.GetHashCode());
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/SparkPost.Acceptance.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | SparkPost.Acceptance
5 | Library
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Always
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/Suppressions.feature:
--------------------------------------------------------------------------------
1 | Feature: Suppressions
2 |
3 | Background:
4 | Given my api key is 'yyy'
5 |
6 | @ignore
7 | Scenario: Adding an email to the suppressions list
8 | Given I have a random email address ending in '@cauthon.com'
9 | When I add my random email address a to my suppressions list
10 | Then it should return a 200
11 | And my random email address should be on my suppressions list
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/SuppressionsSteps.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using TechTalk.SpecFlow;
5 | using Xunit;
6 |
7 | namespace SparkPost.Acceptance
8 | {
9 | [Binding]
10 | public class SuppressionsSteps
11 | {
12 | private readonly ScenarioContext scenarioContext;
13 |
14 | public SuppressionsSteps(ScenarioContext scenarioContext)
15 | {
16 | this.scenarioContext = scenarioContext;
17 | }
18 |
19 | [Given(@"I have a random email address ending in '(.*)'")]
20 | public void y(string email)
21 | {
22 | scenarioContext["randomemail"] = $"{Guid.NewGuid().ToString().Split('-')[0]}{email}";
23 | }
24 |
25 | [When(@"I add my random email address a to my suppressions list")]
26 | public async Task WhenIAddToMySuppressionsList()
27 | {
28 | var email = scenarioContext["randomemail"] as string;
29 |
30 | var client = scenarioContext.Get();
31 |
32 | UpdateSuppressionResponse response = await client.Suppressions.CreateOrUpdate(new[] { email });
33 |
34 | scenarioContext.Set(response);
35 | scenarioContext.Set(response);
36 | }
37 |
38 | [Then(@"my random email address should be on my suppressions list")]
39 | public async Task ThenShouldBeOnMySuppressionsList()
40 | {
41 | var email = scenarioContext["randomemail"] as string;
42 |
43 | var client = scenarioContext.Get();
44 |
45 | ListSuppressionResponse response = null;
46 |
47 | response = await client.Suppressions.Retrieve(email);
48 | Assert.True(response.Suppressions.Any());
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/TransmissionSteps.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using TechTalk.SpecFlow;
4 | using TechTalk.SpecFlow.Assist;
5 |
6 | namespace SparkPost.Acceptance
7 | {
8 | [Binding]
9 | public class TransmissionSteps
10 | {
11 | private readonly ScenarioContext scenarioContext;
12 |
13 | public TransmissionSteps(ScenarioContext scenarioContext)
14 | {
15 | this.scenarioContext = scenarioContext;
16 | }
17 |
18 | [Given(@"I have a new transmission")]
19 | public void GivenIHaveANewTransmissionWith()
20 | {
21 | var transmission = new Transmission();
22 | scenarioContext.Set(transmission);
23 | }
24 |
25 | [Given(@"the transmission is meant to be sent from '(.*)'")]
26 | public void GivenTheTransmissionIsMeantToBeSentfrom(string email)
27 | {
28 | var transmission = scenarioContext.Get();
29 | transmission.Content.From = new Address { Email = email };
30 | scenarioContext.Set(transmission);
31 | }
32 |
33 | [Given(@"the transmission is meant to be sent to '(.*)'")]
34 | public void GivenTheTransmissionIsMeantToBeSentTo(string email)
35 | {
36 | var transmission = scenarioContext.Get();
37 | transmission.Recipients.Add(new Recipient { Address = new Address { Email = email } });
38 | scenarioContext.Set(transmission);
39 | }
40 |
41 | [Given(@"the transmission content is")]
42 | public void GivenTheTransmissionContentIs(Table table)
43 | {
44 | var transmission = scenarioContext.Get();
45 | table.FillInstance(transmission.Content);
46 | scenarioContext.Set(transmission);
47 | }
48 |
49 | [Given(@"the transmission template id is set to '(.*)'")]
50 | public void x(string templateId)
51 | {
52 | var transmission = scenarioContext.Get();
53 |
54 | transmission.Content.TemplateId = templateId;
55 |
56 | scenarioContext.Set(transmission);
57 | }
58 |
59 | [Given(@"the transmission has a text file attachment")]
60 | public void GivenTheTransmissionHasATextFileAttachment()
61 | {
62 | var transmission = scenarioContext.Get();
63 |
64 | var attachment = File.Create("testtextfile.txt");
65 |
66 | transmission.Content.Attachments.Add(attachment);
67 |
68 | scenarioContext.Set(transmission);
69 | }
70 |
71 | [Given(@"the transmission is meant to be CCd to '(.*)'")]
72 | public void GivenTheTransmissionIsMeantToBeCCdTo(string email)
73 | {
74 | var transmission = scenarioContext.Get();
75 |
76 | transmission.Recipients.Add(
77 | new Recipient
78 | {
79 | Type = RecipientType.CC,
80 | Address = new Address { Email = email }
81 | }
82 | );
83 |
84 | scenarioContext.Set(transmission);
85 | }
86 |
87 | [Given(@"the transmission is meant to be BCCd to '(.*)'")]
88 | public void GivenTheTransmissionIsMeantToBeBCCdTo(string email)
89 | {
90 | var transmission = scenarioContext.Get();
91 |
92 | transmission.Recipients.Add(
93 | new Recipient
94 | {
95 | Type = RecipientType.BCC,
96 | Address = new Address { Email = email }
97 | }
98 | );
99 |
100 | scenarioContext.Set(transmission);
101 | }
102 |
103 | [When(@"I send the transmission")]
104 | public async Task WhenISendTheTransmission()
105 | {
106 | var client = scenarioContext.Get();
107 | var transmission = scenarioContext.Get();
108 |
109 | SendTransmissionResponse response = await client.Transmissions.Send(transmission);
110 |
111 | scenarioContext.Set(response);
112 | scenarioContext.Set(response);
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/Transmissions.feature:
--------------------------------------------------------------------------------
1 | Feature: Transmissions
2 |
3 | Background:
4 | Given my api key is 'yyy'
5 |
6 | @ignore
7 | Scenario: Sending a regular email
8 | Given I have a new transmission
9 | And the transmission is meant to be sent from 'darren@cauthon.com'
10 | And the transmission is meant to be sent to 'darren@cauthon.com'
11 | And the transmission content is
12 | | Subject | Html |
13 | | Test Email | this is a test email |
14 | When I send the transmission
15 | Then it should return a 200
16 |
17 | @ignore
18 | Scenario: Sending a regular email with an attachment
19 | Given I have a new transmission
20 | And the transmission is meant to be sent from 'darren@cauthon.com'
21 | And the transmission is meant to be sent to 'darren@cauthon.com'
22 | And the transmission has a text file attachment
23 | And the transmission content is
24 | | Subject | Html |
25 | | Test Email with an attachment | this is a test email |
26 | When I send the transmission
27 | Then it should return a 200
28 |
29 | @ignore
30 | Scenario: Sending a template email with an attachment, which will be ignored and no attachment will be included
31 | Given I have a new transmission
32 | And the transmission is meant to be sent from 'darren@cauthon.com'
33 | And the transmission is meant to be sent to 'darren@cauthon.com'
34 | And the transmission has a text file attachment
35 | And the transmission template id is set to 'my-first-email'
36 | When I send the transmission
37 | Then it should return a 200
38 |
39 | @ignore
40 | Scenario: Using CC/BCC with one direct recipient
41 | Given I have a new transmission
42 | And the transmission is meant to be sent from 'darren@cauthon.com'
43 | And the transmission is meant to be sent to 'darren@cauthon.com'
44 | And the transmission is meant to be CCd to 'darrencauthon@gmail.com'
45 | And the transmission is meant to be BCCd to 'darrencauthon@yahoo.com'
46 | And the transmission content is
47 | | Subject | Html |
48 | | Test Email With CC and BCC (1 recipient) | this is a test email |
49 | When I send the transmission
50 | Then it should return a 200
51 |
52 | @ignore
53 | Scenario: Using CC/BCC with two direct recipients
54 | Given I have a new transmission
55 | And the transmission is meant to be sent from 'darren@cauthon.com'
56 | And the transmission is meant to be sent to 'darrencauthon@hotmail.com'
57 | And the transmission is meant to be sent to 'darren@cauthon.com'
58 | And the transmission is meant to be CCd to 'darrencauthon@gmail.com'
59 | And the transmission is meant to be BCCd to 'darrencauthon@yahoo.com'
60 | And the transmission content is
61 | | Subject | Html |
62 | | Test Email With CC and BCC (2 recipients) | this is a test email |
63 | When I send the transmission
64 | Then it should return a 200
--------------------------------------------------------------------------------
/src/SparkPost.Acceptance/testtextfile.txt:
--------------------------------------------------------------------------------
1 | This is a text file.
--------------------------------------------------------------------------------
/src/SparkPost.Tests/CastAsExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SparkPost.Tests
6 | {
7 | internal static class CastAsExtensions
8 | {
9 | internal static T CastAs(this object dict)
10 | {
11 | return (T)dict;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/ClientTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using Xunit;
4 |
5 | namespace SparkPost.Tests
6 | {
7 | public partial class ClientTests
8 | {
9 | public class HttpClientOverridingTests
10 | {
11 | private readonly Client client;
12 |
13 | public HttpClientOverridingTests()
14 | {
15 | client = new Client(null);
16 | }
17 |
18 | [Fact]
19 | public void By_default_it_should_return_new_http_clients_each_time()
20 | {
21 | var first = client.CustomSettings.CreateANewHttpClient();
22 | var second = client.CustomSettings.CreateANewHttpClient();
23 |
24 | Assert.NotNull(first);
25 | Assert.NotNull(second);
26 | Assert.NotEqual(first, second);
27 | }
28 |
29 | [Fact]
30 | public void It_should_allow_the_overriding_of_the_http_client_building()
31 | {
32 | var httpClient = new HttpClient();
33 |
34 | client.CustomSettings.BuildHttpClientsUsing(() => httpClient);
35 |
36 | Assert.Equal(httpClient, client.CustomSettings.CreateANewHttpClient());
37 | Assert.Equal(httpClient, client.CustomSettings.CreateANewHttpClient());
38 | Assert.Equal(httpClient, client.CustomSettings.CreateANewHttpClient());
39 | Assert.Equal(httpClient, client.CustomSettings.CreateANewHttpClient());
40 | }
41 |
42 | [Fact]
43 | public void it_should_have_inbound_domains()
44 | {
45 | Assert.NotNull(client.InboundDomains);
46 | }
47 |
48 | [Fact]
49 | public void It_should_set_any_subaccount_id_passed_to_it()
50 | {
51 | Assert.Equal(1234, new Client(Guid.NewGuid().ToString(), 1234).SubaccountId);
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/FileTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using Xunit;
4 |
5 | namespace SparkPost.Tests
6 | {
7 | public class FileTests
8 | {
9 | [Fact]
10 | public void It_should_create_correct_type()
11 | {
12 | byte[] content = null;
13 | Assert.IsType(File.Create(content));
14 | Assert.IsType(File.Create(content));
15 | }
16 |
17 | [Theory]
18 | [InlineData("This is some test data.")]
19 | [InlineData("This is some other data.")]
20 | public void It_should_encode_data_correctly(string s)
21 | {
22 | var b = GetBytes(s);
23 | var attach = File.Create(b);
24 | Assert.Equal(EncodeString(s), attach.Data);
25 | }
26 |
27 | [Theory]
28 | [InlineData("foo.png", "image/png")]
29 | [InlineData("foo.txt", "text/plain")]
30 | [InlineData("sf", "application/octet-stream")]
31 | [InlineData("", "application/octet-stream")]
32 | public void It_should_set_name_and_type_correctly(string filename, string mimeType)
33 | {
34 | var b = GetBytes("Some Test Data");
35 | var attach = File.Create(b, filename);
36 | Assert.Equal(filename, attach.Name);
37 | Assert.Equal(mimeType, attach.Type);
38 | }
39 |
40 | private byte[] GetBytes(string input)
41 | {
42 | return Encoding.ASCII.GetBytes(input);
43 | }
44 |
45 | private string EncodeString(string input)
46 | {
47 | return Convert.ToBase64String(GetBytes(input));
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/ListMessageEventsResponseTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace SparkPost.Tests
4 | {
5 | public class ListMessageEventsResponseTests
6 | {
7 | public class DefaultTests
8 | {
9 | [Fact]
10 | public void It_should_not_have_nil_links()
11 | {
12 | var response = new ListMessageEventsResponse();
13 | Assert.NotNull(response.Links);
14 | }
15 |
16 | [Fact]
17 | public void It_should_not_have_nil_events()
18 | {
19 | var response = new ListMessageEventsResponse();
20 | Assert.NotNull(response.MessageEvents);
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/MessageEventsQueryTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace SparkPost.Tests
4 | {
5 | public class MessageEventsQueryTests
6 | {
7 | public class Defaults
8 | {
9 | [Fact]
10 | public void It_should_have_a_default_build_list()
11 | {
12 | Assert.NotNull(new MessageEventsQuery().BounceClasses);
13 | }
14 |
15 | [Fact]
16 | public void It_should_have_a_default_campaign_ids_list()
17 | {
18 | Assert.NotNull(new MessageEventsQuery().CampaignIds);
19 | }
20 |
21 | [Fact]
22 | public void It_should_have_a_default_friendly_froms_list()
23 | {
24 | Assert.NotNull(new MessageEventsQuery().FriendlyFroms);
25 | }
26 |
27 | [Fact]
28 | public void It_should_have_a_default_message_ids_list()
29 | {
30 | Assert.NotNull(new MessageEventsQuery().MessageIds);
31 | }
32 |
33 | [Fact]
34 | public void It_should_have_a_recipients_list()
35 | {
36 | Assert.NotNull(new MessageEventsQuery().Recipients);
37 | }
38 |
39 | [Fact]
40 | public void It_should_have_a_Subaccounts_list()
41 | {
42 | Assert.NotNull(new MessageEventsQuery().Subaccounts);
43 | }
44 |
45 | [Fact]
46 | public void It_should_have_TemplateIds_list()
47 | {
48 | Assert.NotNull(new MessageEventsQuery().TemplateIds);
49 | }
50 |
51 | [Fact]
52 | public void It_should_have_Transmissions_list()
53 | {
54 | Assert.NotNull(new MessageEventsQuery().TransmissionIds);
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/MetricsQueryTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Xunit;
3 |
4 | namespace SparkPost.Tests
5 | {
6 | public class MetricsQueryTests
7 | {
8 | private MetricsQuery _query;
9 |
10 | public MetricsQueryTests()
11 | {
12 | _query = new MetricsQuery();
13 | }
14 |
15 | private void Check(IList list)
16 | {
17 | Assert.NotNull(list);
18 | Assert.Empty(list);
19 | }
20 |
21 | [Fact]
22 | public void It_should_have_a_default_campaigns_list() => Check(_query.Campaigns);
23 |
24 | [Fact]
25 | public void It_should_have_a_default_domains_list() => Check(_query.Domains);
26 |
27 | [Fact]
28 | public void It_should_have_a_default_metrics_list() => Check(_query.Metrics);
29 |
30 | [Fact]
31 | public void It_should_have_a_default_templates_list() => Check(_query.Templates);
32 |
33 | [Fact]
34 | public void It_should_have_a_default_sending_ips_list() => Check(_query.SendingIps);
35 |
36 | [Fact]
37 | public void It_should_have_a_default_ip_pools_list() => Check(_query.IpPools);
38 |
39 | [Fact]
40 | public void It_should_have_a_default_sending_domains_list() => Check(_query.SendingDomains);
41 |
42 | [Fact]
43 | public void It_should_have_a_default_subaccounts_list() => Check(_query.Subaccounts);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/RelayWebhookTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace SparkPost.Tests
4 | {
5 | public class RelayWebhookTests
6 | {
7 | public class DefaultTests
8 | {
9 | [Fact]
10 | public void It_should_initialize_match()
11 | {
12 | Assert.NotNull(new RelayWebhook().Match);
13 | }
14 |
15 | [Fact]
16 | public void It_should_initialize_match_protocol()
17 | {
18 | Assert.Equal("SMTP", new RelayWebhook().Match.Protocol);
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/RequestMethodFinderTests.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.RequestMethods;
2 | using Xunit;
3 |
4 | namespace SparkPost.Tests
5 | {
6 | public class RequestMethodFinderTests
7 | {
8 | public class FindForTests
9 | {
10 | private readonly RequestMethodFinder finder;
11 |
12 | public FindForTests()
13 | {
14 | finder = new RequestMethodFinder(null, null);
15 | }
16 |
17 | [Fact]
18 | public void It_should_return_put_for_put()
19 | {
20 | Assert.IsType(finder.FindFor(new Request { Method = "PUT" }));
21 | }
22 |
23 | [Fact]
24 | public void It_should_return_post_for_post()
25 | {
26 | Assert.IsType(finder.FindFor(new Request { Method = "POST" }));
27 | }
28 |
29 | [Fact]
30 | public void It_should_return_delete_for_delete()
31 | {
32 | Assert.IsType(finder.FindFor(new Request { Method = "DELETE" }));
33 | }
34 |
35 | [Fact]
36 | public void It_should_return_get_for_get()
37 | {
38 | Assert.IsType(finder.FindFor(new Request { Method = "GET" }));
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/RequestMethods/DeleteTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using SparkPost.RequestMethods;
4 | using Xunit;
5 |
6 | namespace SparkPost.Tests.RequestMethods
7 | {
8 | public class DeleteTests
9 | {
10 | public class CanExecuteTests
11 | {
12 | private readonly Delete delete;
13 |
14 | public CanExecuteTests()
15 | {
16 | var httpClient = new HttpClient();
17 | delete = new Delete(httpClient);
18 | }
19 |
20 | [Fact]
21 | public void It_should_return_true_for_delete()
22 | {
23 | var request = new Request { Method = "DELETE" };
24 | Assert.True(delete.CanExecute(request));
25 | }
26 |
27 | [Fact]
28 | public void It_should_return_true_for_delete_lower()
29 | {
30 | var request = new Request { Method = "delete" };
31 | Assert.True(delete.CanExecute(request));
32 | }
33 |
34 | [Fact]
35 | public void It_should_return_true_for_delete_spaces()
36 | {
37 | var request = new Request { Method = "delete " };
38 | Assert.True(delete.CanExecute(request));
39 | }
40 |
41 | [Fact]
42 | public void It_should_return_false_for_others()
43 | {
44 | var request = new Request { Method = Guid.NewGuid().ToString() };
45 | Assert.False(delete.CanExecute(request));
46 | }
47 |
48 | [Fact]
49 | public void It_should_return_false_for_null()
50 | {
51 | var request = new Request { Method = null };
52 | Assert.False(delete.CanExecute(request));
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/RequestMethods/GetTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using Moq;
4 | using SparkPost.RequestMethods;
5 | using Xunit;
6 |
7 | namespace SparkPost.Tests.RequestMethods
8 | {
9 | public class GetTests
10 | {
11 | public class CanExecuteTests
12 | {
13 | private readonly Get get;
14 |
15 | public CanExecuteTests()
16 | {
17 | var httpClient = new HttpClient();
18 | var dataMapper = new Mock();
19 | get = new Get(httpClient, dataMapper.Object);
20 | }
21 |
22 | [Fact]
23 | public void It_should_return_true_for_get()
24 | {
25 | var request = new Request { Method = "GET" };
26 | Assert.True(get.CanExecute(request));
27 | }
28 |
29 | [Fact]
30 | public void It_should_return_true_for_get_lower()
31 | {
32 | var request = new Request { Method = "get" };
33 | Assert.True(get.CanExecute(request));
34 | }
35 |
36 | [Fact]
37 | public void It_should_return_true_for_get_spacing()
38 | {
39 | var request = new Request { Method = "get " };
40 | Assert.True(get.CanExecute(request));
41 | }
42 |
43 | [Fact]
44 | public void It_should_return_false_for_others()
45 | {
46 | var request = new Request { Method = Guid.NewGuid().ToString() };
47 | Assert.False(get.CanExecute(request));
48 | }
49 |
50 | [Fact]
51 | public void It_should_return_false_for_null()
52 | {
53 | var request = new Request { Method = null };
54 | Assert.False(get.CanExecute(request));
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/RequestMethods/PostTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using SparkPost.RequestMethods;
4 | using Xunit;
5 |
6 | namespace SparkPost.Tests.RequestMethods
7 | {
8 | public class PostTests
9 | {
10 | public class CanExecuteTests
11 | {
12 | private readonly Post post;
13 |
14 | public CanExecuteTests()
15 | {
16 | var httpClient = new HttpClient();
17 | post = new Post(httpClient);
18 | }
19 |
20 | [Fact]
21 | public void It_should_return_true_for_post()
22 | {
23 | var request = new Request { Method = "POST" };
24 | Assert.True(post.CanExecute(request));
25 | }
26 |
27 | [Fact]
28 | public void It_should_return_true_for_post_lower()
29 | {
30 | var request = new Request { Method = "post" };
31 | Assert.True(post.CanExecute(request));
32 | }
33 |
34 | [Fact]
35 | public void It_should_return_true_for_post_spaces()
36 | {
37 | var request = new Request { Method = "post " };
38 | Assert.True(post.CanExecute(request));
39 | }
40 |
41 | [Fact]
42 | public void It_should_return_false_for_others()
43 | {
44 | var request = new Request { Method = Guid.NewGuid().ToString() };
45 | Assert.False(post.CanExecute(request));
46 | }
47 |
48 | [Fact]
49 | public void It_should_return_false_for_nil()
50 | {
51 | var request = new Request { Method = null };
52 | Assert.False(post.CanExecute(request));
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/RequestMethods/PutTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using SparkPost.RequestMethods;
4 | using Xunit;
5 |
6 | namespace SparkPost.Tests.RequestMethods
7 | {
8 | public class PutTests
9 | {
10 | public class CanExecuteTests
11 | {
12 | private readonly Put put;
13 |
14 | public CanExecuteTests()
15 | {
16 | var httpClient = new HttpClient();
17 | put = new Put(httpClient);
18 | }
19 |
20 | [Fact]
21 | public void It_should_return_true_for_put()
22 | {
23 | var request = new Request { Method = "PUT" };
24 | Assert.True(put.CanExecute(request));
25 | }
26 |
27 | [Fact]
28 | public void It_should_return_true_for_put_lower()
29 | {
30 | var request = new Request { Method = "put" };
31 | Assert.True(put.CanExecute(request));
32 | }
33 |
34 | [Fact]
35 | public void It_should_return_true_for_put_json()
36 | {
37 | var request = new Request { Method = "PUT JSON" };
38 | Assert.True(put.CanExecute(request));
39 | }
40 |
41 | [Fact]
42 | public void It_should_return_false_for_others()
43 | {
44 | var request = new Request { Method = Guid.NewGuid().ToString() };
45 | Assert.False(put.CanExecute(request));
46 | }
47 |
48 | [Fact]
49 | public void It_should_return_false_for_nil()
50 | {
51 | var request = new Request { Method = null };
52 | Assert.False(put.CanExecute(request));
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/SparkPost.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | SparkPost.Tests
5 | Library
6 |
7 |
8 |
9 |
10 |
11 |
12 | all
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/SubaccountTest.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost.Tests
2 | {
3 | public class SubaccountTests { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/UserAgentTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 |
4 | namespace SparkPost.Tests
5 | {
6 | public partial class ClientTests
7 | {
8 | public partial class UserAgentTests
9 | {
10 | private readonly Client.Settings settings;
11 |
12 | public UserAgentTests()
13 | {
14 | settings = new Client.Settings();
15 | }
16 |
17 | [Fact]
18 | public void It_should_default_to_the_library_version()
19 | {
20 | Assert.StartsWith($"csharp-sparkpost/2.", settings.UserAgent);
21 | }
22 |
23 | [Fact]
24 | public void It_should_allow_the_user_agent_to_be_changed()
25 | {
26 | var userAgent = Guid.NewGuid().ToString();
27 | settings.UserAgent = userAgent;
28 | Assert.Equal(userAgent, settings.UserAgent);
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/Utilities/SnakeCaseTests.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.Utilities;
2 | using Xunit;
3 |
4 | namespace SparkPost.Tests.Utilities
5 | {
6 | public class SnakeCaseTests
7 | {
8 | [Fact]
9 | public void It_should_convert_things_to_snake_case()
10 | {
11 | Assert.Equal("t", SnakeCase.Convert("T"));
12 | Assert.Equal("test", SnakeCase.Convert("Test"));
13 | Assert.Equal("t_e_s_t", SnakeCase.Convert("TEST"));
14 | Assert.Equal("john_galt", SnakeCase.Convert("JohnGalt"));
15 | }
16 |
17 | [Fact]
18 | public void It_should_handle_harder_strings()
19 | {
20 | Assert.Equal("test_testing", SnakeCase.Convert("TestTesting"));
21 | Assert.Equal("testing_test", SnakeCase.Convert("TestingTest"));
22 | Assert.Equal("appppp_appppppp", SnakeCase.Convert("ApppppAppppppp"));
23 | Assert.Equal("appppppp_appppp", SnakeCase.Convert("ApppppppAppppp"));
24 | }
25 |
26 | [Fact]
27 | public void It_should_convert_null_to_null()
28 | {
29 | Assert.Null(SnakeCase.Convert(null));
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/SparkPost.Tests/WebhookTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace SparkPost.Tests
4 | {
5 | public class WebhookTests
6 | {
7 | public class DefaultTests
8 | {
9 | [Fact]
10 | public void It_should_initialize_events()
11 | {
12 | Assert.NotNull(new Webhook().Events);
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/SparkPost.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkPost", "SparkPost\SparkPost.csproj", "{A5DDA3E3-7B3D-46C3-B4BB-C627FBA37812}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkPost.Tests", "SparkPost.Tests\SparkPost.Tests.csproj", "{52F2F4F4-3DE2-49C6-87D8-BD6F825B9372}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkPost.Acceptance", "SparkPost.Acceptance\SparkPost.Acceptance.csproj", "{8F62193B-1C44-4E92-96C7-8EBD610F7669}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SendTemplate", "..\examples\SendTemplate\SendTemplate.csproj", "{A85DDE10-EBD6-4B58-93D6-185809C73FE8}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{1DC64ED8-82FD-4640-90F3-BD487C809039}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SendInline", "..\examples\SendInline\SendInline.csproj", "{8D45D223-E1FE-4652-A37E-09507AC4E107}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CC", "..\examples\CC\CC.csproj", "{2B086611-A56B-4857-9F7F-A8603D7AA3FD}"
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BCC", "..\examples\BCC\BCC.csproj", "{16978032-B34C-44B6-8DA1-475D751338F1}"
21 | EndProject
22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "build", "..\build\build.csproj", "{C68B2B1C-B5A9-4E97-8971-2ACDFF94A6B2}"
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|Any CPU = Debug|Any CPU
27 | Release|Any CPU = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {A5DDA3E3-7B3D-46C3-B4BB-C627FBA37812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {A5DDA3E3-7B3D-46C3-B4BB-C627FBA37812}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {A5DDA3E3-7B3D-46C3-B4BB-C627FBA37812}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {A5DDA3E3-7B3D-46C3-B4BB-C627FBA37812}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {52F2F4F4-3DE2-49C6-87D8-BD6F825B9372}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {52F2F4F4-3DE2-49C6-87D8-BD6F825B9372}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {52F2F4F4-3DE2-49C6-87D8-BD6F825B9372}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {52F2F4F4-3DE2-49C6-87D8-BD6F825B9372}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {8F62193B-1C44-4E92-96C7-8EBD610F7669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {8F62193B-1C44-4E92-96C7-8EBD610F7669}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {8F62193B-1C44-4E92-96C7-8EBD610F7669}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {8F62193B-1C44-4E92-96C7-8EBD610F7669}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {A85DDE10-EBD6-4B58-93D6-185809C73FE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {A85DDE10-EBD6-4B58-93D6-185809C73FE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {A85DDE10-EBD6-4B58-93D6-185809C73FE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {A85DDE10-EBD6-4B58-93D6-185809C73FE8}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {8D45D223-E1FE-4652-A37E-09507AC4E107}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {8D45D223-E1FE-4652-A37E-09507AC4E107}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {8D45D223-E1FE-4652-A37E-09507AC4E107}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {8D45D223-E1FE-4652-A37E-09507AC4E107}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {2B086611-A56B-4857-9F7F-A8603D7AA3FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {2B086611-A56B-4857-9F7F-A8603D7AA3FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {2B086611-A56B-4857-9F7F-A8603D7AA3FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {2B086611-A56B-4857-9F7F-A8603D7AA3FD}.Release|Any CPU.Build.0 = Release|Any CPU
54 | {16978032-B34C-44B6-8DA1-475D751338F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {16978032-B34C-44B6-8DA1-475D751338F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {16978032-B34C-44B6-8DA1-475D751338F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 | {16978032-B34C-44B6-8DA1-475D751338F1}.Release|Any CPU.Build.0 = Release|Any CPU
58 | {C68B2B1C-B5A9-4E97-8971-2ACDFF94A6B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59 | {C68B2B1C-B5A9-4E97-8971-2ACDFF94A6B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
60 | {C68B2B1C-B5A9-4E97-8971-2ACDFF94A6B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
61 | {C68B2B1C-B5A9-4E97-8971-2ACDFF94A6B2}.Release|Any CPU.Build.0 = Release|Any CPU
62 | EndGlobalSection
63 | GlobalSection(SolutionProperties) = preSolution
64 | HideSolutionNode = FALSE
65 | EndGlobalSection
66 | GlobalSection(NestedProjects) = preSolution
67 | {A85DDE10-EBD6-4B58-93D6-185809C73FE8} = {1DC64ED8-82FD-4640-90F3-BD487C809039}
68 | {8D45D223-E1FE-4652-A37E-09507AC4E107} = {1DC64ED8-82FD-4640-90F3-BD487C809039}
69 | {2B086611-A56B-4857-9F7F-A8603D7AA3FD} = {1DC64ED8-82FD-4640-90F3-BD487C809039}
70 | {16978032-B34C-44B6-8DA1-475D751338F1} = {1DC64ED8-82FD-4640-90F3-BD487C809039}
71 | EndGlobalSection
72 | EndGlobal
73 |
--------------------------------------------------------------------------------
/src/SparkPost/Address.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class Address
4 | {
5 | public string Name { get; set; }
6 | public string Email { get; set; }
7 | public string HeaderTo { get; set; }
8 |
9 | public Address() { }
10 |
11 | public Address(string email) : this(email, null, null) { }
12 |
13 | public Address(string email, string name) : this(email, name, null) { }
14 |
15 | public Address(string email, string name, string headerTo)
16 | {
17 | this.Email = email;
18 | this.Name = name;
19 | this.HeaderTo = headerTo;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/SparkPost/Attachment.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class Attachment : File { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/SparkPost/Attributes.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class Attributes
4 | {
5 | public Attributes() { }
6 |
7 | public int InternalId { get; set; }
8 |
9 | public int ListGroupId { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/SparkPost/BounceCategory.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | // The list was taken from:
4 | // https://support.sparkpost.com/customer/portal/articles/1929896
5 |
6 | public enum BounceCategory
7 | {
8 | ///
9 | /// None or unable to parse.
10 | ///
11 | Undefined,
12 |
13 | ///
14 | /// The response text could not be identified.
15 | ///
16 | Undetermined,
17 |
18 | ///
19 | /// Hard bounce: Invalid recipient, no recipient.
20 | ///
21 | Hard,
22 |
23 | ///
24 | /// Soft bounce: soft bounced, DNS failure, MX record not found, mailbox is full, message too large, timeout, delayed, auto-reply, unspecified reason.
25 | ///
26 | Soft,
27 |
28 | ///
29 | /// The message was failed by Momentum's (SparkPost) configured policies or the message is a subscribe request.
30 | ///
31 | Admin,
32 |
33 | ///
34 | /// The message was blocked by the receiver (spam).
35 | ///
36 | Block
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/SparkPost/BounceClass.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | // The list was taken from:
4 | // https://support.sparkpost.com/customer/portal/articles/1929896
5 |
6 | public enum BounceClass
7 | {
8 | ///
9 | /// None or unable to parse.
10 | ///
11 | Undefined = 0,
12 |
13 | ///
14 | /// Undetermined
15 | /// The response text could not be identified.
16 | /// Category: Undetermined.
17 | ///
18 | Undetermined = 1,
19 |
20 | ///
21 | /// Invalid Recipient
22 | /// The recipient is invalid.
23 | /// Category: Hard.
24 | ///
25 | InvalidRecipient = 10,
26 |
27 | ///
28 | /// Soft Bounce
29 | /// The message soft bounced.
30 | /// Category: Soft.
31 | ///
32 | SoftBounce = 20,
33 |
34 | ///
35 | /// DNS Failure
36 | /// The message bounced due to a DNS failure.
37 | /// Category: Soft.
38 | ///
39 | DnsFailure = 21,
40 |
41 | ///
42 | /// Mailbox Full
43 | /// The message bounced due to the remote mailbox being over quota.
44 | /// Category: Soft.
45 | ///
46 | MailboxFull = 22,
47 |
48 | ///
49 | /// Too Large
50 | /// The message bounced because it was too large for the recipient.
51 | /// Category: Soft.
52 | ///
53 | TooLarge = 23,
54 |
55 | ///
56 | /// Timeout
57 | /// The message timed out.
58 | /// Category: Soft.
59 | ///
60 | Timeout = 24,
61 |
62 | ///
63 | /// Admin Failure
64 | /// The message was failed by Momentum's configured policies.
65 | /// Category: Admin.
66 | ///
67 | AdminFailure = 25,
68 |
69 | ///
70 | /// Generic Bounce: No RCPT
71 | /// No recipient could be determined for the message.
72 | /// Category: Hard.
73 | ///
74 | GenericBounceNoRecipient = 30,
75 |
76 | ///
77 | /// Generic Bounce
78 | /// The message failed for unspecified reasons.
79 | /// Category: Soft.
80 | ///
81 | GenericBounce = 40,
82 |
83 | ///
84 | /// Mail Block
85 | /// The message was blocked by the receiver.
86 | /// Category: Block.
87 | ///
88 | MailBlock = 50,
89 |
90 | ///
91 | /// Spam Block
92 | /// The message was blocked by the receiver as coming from a known spam source.
93 | /// Category: Block.
94 | ///
95 | SpamBlock = 51,
96 |
97 | ///
98 | /// Spam Content
99 | /// The message was blocked by the receiver as spam.
100 | /// Category: Block.
101 | ///
102 | SpamContent = 52,
103 |
104 | ///
105 | /// Prohibited Attachment
106 | /// The message was blocked by the receiver because it contained an attachment.
107 | /// Category: Block.
108 | ///
109 | ProhibitedAttachment = 53,
110 |
111 | ///
112 | /// Relaying Denied
113 | /// The message was blocked by the receiver because relaying is not allowed.
114 | /// Category: Block.
115 | ///
116 | RelayingDenied = 54,
117 |
118 | ///
119 | /// Auto-Reply
120 | /// The message is an auto-reply/vacation mail.
121 | /// Category: Soft.
122 | ///
123 | AutoReply = 60,
124 |
125 | ///
126 | /// Transient Failure
127 | /// Message transmission has been temporarily delayed.
128 | /// Category: Soft.
129 | ///
130 | TransientFailure = 70,
131 |
132 | ///
133 | /// Subscribe
134 | /// The message is a subscribe request.
135 | /// Category: Admin.
136 | ///
137 | Subscribe = 80,
138 |
139 | ///
140 | /// Unsubscribe
141 | /// The message is an unsubscribe request.
142 | /// Category: Hard.
143 | ///
144 | Unsubscribe = 90,
145 |
146 | ///
147 | /// Challenge-Response
148 | /// The message is a challenge-response probe.
149 | /// Category: Soft.
150 | ///
151 | ChallengeResponse = 100
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/SparkPost/BounceClassDetails.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class BounceClassDetails
4 | {
5 | public BounceClass BounceClass { get; set; }
6 | public string Name { get; set; }
7 | public string Description { get; set; }
8 | public BounceCategory Category { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/SparkPost/CcHandling.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace SparkPost
7 | {
8 | internal static class CcHandling
9 | {
10 | internal static void Process(Transmission transmission, IDictionary result)
11 | {
12 | var recipients = transmission.Recipients;
13 | if (recipients.All(RecipientTypeIsTo))
14 | return;
15 |
16 | var toRecipient = recipients.FirstOrDefault(RecipientTypeIsTo);
17 | if (recipients.Count(RecipientTypeIsTo) == 1 && toRecipient.Address != null)
18 | DoStandardCcRewriting(recipients, result);
19 | else
20 | SetAnyCCsInTheHeader(recipients, result);
21 | }
22 |
23 | private static void DoStandardCcRewriting(IEnumerable recipients, IDictionary result)
24 | {
25 | var toRecipient = recipients.Single(RecipientTypeIsTo);
26 | var toName = toRecipient.Address.Name;
27 | var toEmail = toRecipient.Address.Email;
28 |
29 | var ccRecipients = recipients.Where(RecipientTypeIsCC);
30 | if (ccRecipients.Any())
31 | {
32 | var ccHeader = GetCcHeader(ccRecipients);
33 | if (!String.IsNullOrWhiteSpace(ccHeader))
34 | SetTheCcHeader(result, ccHeader);
35 | }
36 |
37 | var resultRecipients = (result["recipients"] as IEnumerable>).ToList();
38 | SetFieldsOnRecipients(resultRecipients, toName, toEmail);
39 | result["recipients"] = resultRecipients;
40 | }
41 |
42 | private static void SetAnyCCsInTheHeader(IEnumerable recipients, IDictionary result)
43 | {
44 | var ccs = GetTheCcEmails(recipients);
45 |
46 | if (ccs.Any() == false)
47 | return;
48 |
49 | string ccHeader = FormatTheCCs(ccs);
50 | SetTheCcHeader(result, ccHeader);
51 | }
52 |
53 | private static IEnumerable GetTheCcEmails(IEnumerable recipients)
54 | {
55 | return recipients
56 | .Where(x => x.Type == RecipientType.CC)
57 | .Where(x => x.Address != null)
58 | .Where(x => string.IsNullOrWhiteSpace(x.Address.Email) == false)
59 | .Select(x => x.Address.Email);
60 | }
61 |
62 | private static string FormatTheCCs(IEnumerable ccs)
63 | {
64 | return string.Join(",", ccs.Select(x => "<" + x + ">"));
65 | }
66 |
67 | private static void SetTheCcHeader(IDictionary result, string header)
68 | {
69 | MakeSureThereIsAHeaderDefinedInTheRequest(result);
70 | SetThisHeaderValue(result, "CC", header);
71 | }
72 |
73 | private static bool RecipientTypeIsTo(Recipient recipient)
74 | {
75 | return recipient.Type == RecipientType.To;
76 | }
77 |
78 | private static bool RecipientTypeIsCC(Recipient recipient)
79 | {
80 | return recipient.Type == RecipientType.CC;
81 | }
82 |
83 | private static void SetFieldsOnRecipients(IEnumerable> recipients, string name, string email)
84 | {
85 | var addresses = recipients.Where(r => r.ContainsKey("address")).Select(r => r["address"]).Cast>();
86 |
87 | foreach (var address in addresses)
88 | {
89 | if (!String.IsNullOrWhiteSpace(name))
90 | address["name"] = name;
91 | if (!String.IsNullOrWhiteSpace(email))
92 | address["header_to"] = email;
93 | }
94 | }
95 |
96 | private static string GetCcHeader(IEnumerable recipients)
97 | {
98 | var listOfFormattedAddresses = recipients.Select(FormatedAddress).Where(fa => !String.IsNullOrWhiteSpace(fa));
99 | return listOfFormattedAddresses.Any() ? String.Join(", ", listOfFormattedAddresses) : null;
100 | }
101 |
102 | private static string FormatedAddress(Recipient recipient)
103 | {
104 | var address = recipient.Address;
105 |
106 | if (string.IsNullOrWhiteSpace(address?.Email))
107 | return null;
108 |
109 | var email = address.Email.Trim();
110 |
111 | if (string.IsNullOrWhiteSpace(address.Name))
112 | return email;
113 |
114 | var name = Regex.IsMatch(address.Name, @"[^\w ]") ? $"\"{address.Name}\"" : address.Name;
115 | return $"{name} <{email}>";
116 | }
117 |
118 | private static void MakeSureThereIsAHeaderDefinedInTheRequest(IDictionary result)
119 | {
120 | if (result.ContainsKey("content") == false)
121 | result["content"] = new Dictionary();
122 |
123 | var content = result["content"] as IDictionary;
124 | if (content.ContainsKey("headers") == false)
125 | content["headers"] = new Dictionary();
126 | }
127 |
128 | private static void SetThisHeaderValue(IDictionary result, string key, string value)
129 | {
130 | ((IDictionary)((IDictionary)result["content"])["headers"])[key] = value;
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/SparkPost/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Net.Http;
4 | using SparkPost.RequestSenders;
5 | using SparkPost.Utilities;
6 |
7 | namespace SparkPost
8 | {
9 | public class Client : IClient
10 | {
11 | private const string defaultApiHost = "https://api.sparkpost.com";
12 |
13 | public Client(string apiKey) : this(apiKey, defaultApiHost, 0) { }
14 |
15 | public Client(string apiKey, string apiHost) : this(apiKey, apiHost, 0) { }
16 |
17 | public Client(string apiKey, long subAccountId) : this(apiKey, defaultApiHost, subAccountId) { }
18 |
19 | public Client(string apiKey, string apiHost, long subAccountId)
20 | {
21 | ApiKey = apiKey;
22 | ApiHost = apiHost;
23 | SubaccountId = subAccountId;
24 |
25 | var dataMapper = new DataMapper(Version);
26 | var requestSender = new RequestSender(this, dataMapper);
27 |
28 | SendingDomains = new SendingDomains(this, requestSender, dataMapper);
29 | Transmissions = new Transmissions(this, requestSender, dataMapper);
30 | Suppressions = new Suppressions(this, requestSender, dataMapper);
31 | Webhooks = new Webhooks(this, requestSender, dataMapper);
32 | Subaccounts = new Subaccounts(this, requestSender, dataMapper);
33 | MessageEvents = new MessageEvents(this, requestSender);
34 | InboundDomains = new InboundDomains(this, requestSender, dataMapper);
35 | RelayWebhooks = new RelayWebhooks(this, requestSender, dataMapper);
36 | RecipientValidations = new RecipientValidation(this, requestSender);
37 | RecipientLists = new RecipientLists(this, requestSender, dataMapper);
38 | Templates = new Templates(this, requestSender, dataMapper);
39 | Metrics = new Metrics(this, requestSender);
40 | Events = new Events(this, requestSender);
41 | CustomSettings = new Settings();
42 | }
43 |
44 | public string ApiKey { get; set; }
45 | public string ApiHost { get; set; }
46 | public long SubaccountId { get; set; }
47 |
48 | public ISendingDomains SendingDomains { get; }
49 | public ITransmissions Transmissions { get; }
50 | public ISuppressions Suppressions { get; }
51 | public IWebhooks Webhooks { get; }
52 | public ISubaccounts Subaccounts { get; }
53 | public IMessageEvents MessageEvents { get; }
54 | public IInboundDomains InboundDomains { get; }
55 | public IRelayWebhooks RelayWebhooks { get; }
56 | public IRecipientLists RecipientLists { get; }
57 | public ITemplates Templates { get; }
58 | public IMetrics Metrics { get; }
59 |
60 | public IRecipientValidation RecipientValidations { get; }
61 |
62 | public Events Events { get; }
63 | public string Version => "v1";
64 |
65 | public Settings CustomSettings { get; }
66 |
67 | public class Settings
68 | {
69 | private Func httpClientBuilder;
70 |
71 | public Settings()
72 | {
73 | httpClientBuilder = () =>
74 | {
75 | var httpClient = new HttpClient();
76 | httpClient.DefaultRequestHeaders.Accept.Clear();
77 | return httpClient;
78 | };
79 |
80 | var currentVersion = GetTheCurrentVersion();
81 | if (string.IsNullOrEmpty(currentVersion) == false)
82 | UserAgent = $"csharp-sparkpost/{currentVersion}";
83 | }
84 |
85 | public string UserAgent { get; set; }
86 |
87 | public HttpClient CreateANewHttpClient()
88 | {
89 | return httpClientBuilder();
90 | }
91 |
92 | public void BuildHttpClientsUsing(Func httpClient)
93 | {
94 | httpClientBuilder = httpClient;
95 | }
96 |
97 | private static string GetTheCurrentVersion()
98 | {
99 | try
100 | {
101 | return AttemptToPullTheVersionNumberOutOf(typeof(Client).AssemblyQualifiedName);
102 | }
103 | catch
104 | {
105 | return null;
106 | }
107 | }
108 |
109 | private static string AttemptToPullTheVersionNumberOutOf(string value)
110 | {
111 | return value.SplitOn("Version=")[1].SplitOn(",")[0].SplitOn(".").Take(3).JoinWith(".");
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/SparkPost/Content.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SparkPost
4 | {
5 | public class Content
6 | {
7 | public Content()
8 | {
9 | From = new Address();
10 | Headers = new Dictionary();
11 | Attachments = new List();
12 | InlineImages = new List();
13 | }
14 |
15 | public string Html { get; set; }
16 | public string Text { get; set; }
17 | public string Subject { get; set; }
18 | public Address From { get; set; }
19 | public string ReplyTo { get; set; }
20 | public IDictionary Headers { get; set; }
21 | public IList Attachments { get; set; }
22 | public IList InlineImages { get; set; }
23 | public string TemplateId { get; set; }
24 | public bool? UseDraftTemplate { get; set; }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/SparkPost/CreateSendingDomainResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class CreateSendingDomainResponse : Response
4 | {
5 | public string Domain { get; set; }
6 |
7 | public Dkim Dkim { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/CreateSubaccountResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class CreateSubaccountResponse : Response
4 | {
5 | public int SubaccountId { get; set; }
6 | public string Key { get; set; }
7 | public string Label { get; set; }
8 | public string ShortKey { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/SparkPost/CreateTemplateResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SparkPost
8 | {
9 | public class CreateTemplateResponse : Response
10 | {
11 | public string Id { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/SparkPost/Dkim.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class Dkim
4 | {
5 | public string SigningDomain { get; set; }
6 |
7 | public string PrivateKey { get; set; }
8 |
9 | public string PublicKey { get; set; }
10 |
11 | public string Selector { get; set; }
12 |
13 | public string Headers { get; set; }
14 |
15 | ///
16 | /// Convert json result form Sparkpost API to Dkim.
17 | ///
18 | /// Json result form Sparkpost API.
19 | ///
20 | public static Dkim ConvertToDkim(dynamic result)
21 | {
22 | return result != null
23 | ? new Dkim
24 | {
25 | SigningDomain = result["public"],
26 | PublicKey = result["private"],
27 | Selector = result.selector,
28 | Headers = result.headers
29 | }
30 | : null;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/SparkPost/Dns.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class Dns
4 | {
5 | public string DkimRecord { get; set; }
6 |
7 | public string SpfRecord { get; set; }
8 |
9 | public string DkimError { get; set; }
10 |
11 | public string SpfError { get; set; }
12 |
13 | ///
14 | /// Convert json result form Sparkpost API to Dns.
15 | ///
16 | /// Json result form Sparkpost API.
17 | ///
18 | public static Dns ConvertToDns(dynamic result)
19 | {
20 | return result != null
21 | ? new Dns
22 | {
23 | DkimError = result.dkim_error,
24 | DkimRecord = result.dkim_record,
25 | SpfError = result.spf_error,
26 | SpfRecord = result.spf_record
27 | }
28 | : null;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/SparkPost/EmailValidationResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class EmailValidationResponse
4 | {
5 | public string Result { get; set; }
6 | public bool Valid { get; set; }
7 | public string Reason { get; set; }
8 | public bool IsRole { get; set; }
9 | public bool IsDisposable { get; set; }
10 | public int DeliveryConfidence { get; set; }
11 | public bool IsFree { get; set; }
12 |
13 | public static EmailValidationResponse ConvertToResponse(dynamic r) =>
14 | new EmailValidationResponse
15 | {
16 | Result = r.result,
17 | Valid = r.valid,
18 | Reason = r.reason ?? string.Empty,
19 | IsRole = r.is_role,
20 | IsDisposable = r.is_disposable,
21 | DeliveryConfidence = r.delivery_confidence,
22 | IsFree = r.is_free
23 | };
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/SparkPost/Events.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using Newtonsoft.Json;
5 | using Newtonsoft.Json.Linq;
6 | using SparkPost.RequestSenders;
7 | using SparkPost.Utilities;
8 |
9 | namespace SparkPost
10 | {
11 | public class Events
12 | {
13 | private readonly Client client;
14 | private readonly IRequestSender requestSender;
15 |
16 | public Events(Client client, IRequestSender requestSender)
17 | {
18 | this.client = client;
19 | this.requestSender = requestSender;
20 | }
21 |
22 | public async Task Get(string cursor = "initial", int perPage = 1000)
23 | {
24 | var request = new Request { Url = $"api/{client.Version}/events/message?perPage={perPage}&cursor={cursor}", Method = "GET" };
25 |
26 | var response = await requestSender.Send(request);
27 | if (response.StatusCode != HttpStatusCode.OK)
28 | {
29 | throw new ResponseException(response);
30 | }
31 | var results = Jsonification.DeserializeObject(response.Content);
32 | return results;
33 | }
34 |
35 | public async Task GetEventsSince(DateTime fromTime, int perPage = 1000)
36 | {
37 | var request = new Request
38 | {
39 | Url = $"api/{client.Version}/events/message?perPage={perPage}&from={fromTime:yyyy-MM-ddTHH:mm:ssZ}",
40 | Method = "GET"
41 | };
42 |
43 | var response = await requestSender.Send(request);
44 | if (response.StatusCode != HttpStatusCode.OK)
45 | {
46 | throw new ResponseException(response);
47 | }
48 | var results = Jsonification.DeserializeObject(response.Content);
49 | return results;
50 | }
51 |
52 | public async Task GetEventsNext(string nextUri)
53 | {
54 | var request = new Request { Url = nextUri, Method = "GET" };
55 |
56 | var response = await requestSender.Send(request);
57 | if (response.StatusCode != HttpStatusCode.OK)
58 | {
59 | throw new ResponseException(response);
60 | }
61 | var results = Jsonification.DeserializeObject(response.Content);
62 | return results;
63 | }
64 | }
65 |
66 | public class JsonEventResponse
67 | {
68 | [JsonProperty("results")]
69 | public JObject[] Results { get; set; }
70 |
71 | [JsonProperty("total_count")]
72 | public int TotalCount { get; set; }
73 | public Links Links { get; set; }
74 | }
75 |
76 | public class Links
77 | {
78 | public string Next { get; set; }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/SparkPost/File.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Web;
4 |
5 | namespace SparkPost
6 | {
7 | public abstract class File
8 | {
9 | public string Type { get; set; }
10 | public string Name { get; set; }
11 | public string Data { get; set; }
12 |
13 | public static T Create(string filename) where T : File, new()
14 | {
15 | var content = System.IO.File.ReadAllBytes(filename);
16 | return Create(content, Path.GetFileName(filename));
17 | }
18 |
19 | public static T Create(string filename, string name) where T : File, new()
20 | {
21 | var result = Create(filename);
22 | result.Name = name;
23 | return result;
24 | }
25 |
26 | public static T Create(byte[] content) where T : File, new()
27 | {
28 | return Create(content, String.Empty);
29 | }
30 |
31 | public static T Create(byte[] content, string name) where T : File, new()
32 | {
33 | var result = new T();
34 | if (content != null)
35 | {
36 | result.Data = Convert.ToBase64String(content);
37 | result.Type = MimeMapping.MimeUtility.GetMimeMapping(name);
38 | result.Name = name;
39 | }
40 | ;
41 | return result;
42 | }
43 |
44 | public static T Create(Stream content) where T : File, new()
45 | {
46 | return Create(content, String.Empty);
47 | }
48 |
49 | public static T Create(Stream content, string name) where T : File, new()
50 | {
51 | using (var ms = new MemoryStream())
52 | {
53 | content.CopyTo(ms);
54 | return Create(ms.ToArray(), name);
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/SparkPost/GetMetricsResourceResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SparkPost
8 | {
9 | public class GetMetricsResourceResponse : Response
10 | {
11 | public IList Results { get; set; }
12 |
13 | public GetMetricsResourceResponse()
14 | {
15 | Results = new List();
16 | }
17 |
18 | public GetMetricsResourceResponse(Response source)
19 | {
20 | this.SetFrom(source);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/SparkPost/GetMetricsResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SparkPost
8 | {
9 | public class GetMetricsResponse : Response
10 | {
11 | public IList> Results { get; set; }
12 |
13 | public GetMetricsResponse()
14 | {
15 | Results = new List>();
16 | }
17 |
18 | public GetMetricsResponse(Response source)
19 | {
20 | this.SetFrom(source);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/SparkPost/GetSendingDomainResponse.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace SparkPost
4 | {
5 | public class GetSendingDomainResponse : Response
6 | {
7 | public SendingDomain SendingDomain { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/IClient.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | ///
4 | /// Provides access to the SparkPost API.
5 | ///
6 | public interface IClient
7 | {
8 | ///
9 | /// Gets or sets the key used for requests to the SparkPost API.
10 | ///
11 | string ApiKey { get; set; }
12 |
13 | ///
14 | /// Gets or sets the base URL of the SparkPost API.
15 | ///
16 | string ApiHost { get; set; }
17 |
18 | ///
19 | /// Gets access to the transmissions resource of the SparkPost API.
20 | ///
21 | ITransmissions Transmissions { get; }
22 |
23 | ///
24 | /// Gets access to the suppressions resource of the SparkPost API.
25 | ///
26 | ISuppressions Suppressions { get; }
27 |
28 | ///
29 | /// Gets access to the subaccounts resource of the SparkPost API.
30 | ///
31 | ISubaccounts Subaccounts { get; }
32 |
33 | ///
34 | /// Gets access to the webhooks resource of the SparkPost API.
35 | ///
36 | IWebhooks Webhooks { get; }
37 |
38 | ///
39 | /// Gets access to the message events resource of the SparkPost API.
40 | ///
41 | IMessageEvents MessageEvents { get; }
42 |
43 | ///
44 | /// Gets access to the inbound domains resource of the SparkPost API.
45 | ///
46 | IInboundDomains InboundDomains { get; }
47 |
48 | ///
49 | /// Gets access to the sending domains resource of the SparkPost API.
50 | ///
51 | ISendingDomains SendingDomains { get; }
52 |
53 | ///
54 | /// Gets access to the relay webhooks resource of the SparkPost API.
55 | ///
56 | IRelayWebhooks RelayWebhooks { get; }
57 |
58 | IRecipientLists RecipientLists { get; }
59 |
60 | ///
61 | /// Gets access to the Templates resource of the SparkPost API.
62 | ///
63 | ITemplates Templates { get; }
64 |
65 | ///
66 | /// Gets access to the metrics resource of the SparkPost API.
67 | ///
68 | IMetrics Metrics { get; }
69 |
70 | ///
71 | /// Gets access to the Email Recipient Validation resource of the SparkPost API.
72 | ///
73 | IRecipientValidation RecipientValidations { get; }
74 |
75 | ///
76 | /// Gets the API version supported by this client.
77 | ///
78 | string Version { get; }
79 |
80 | ///
81 | /// Get the custom settings for this client.
82 | ///
83 | Client.Settings CustomSettings { get; }
84 |
85 | ///
86 | /// Gets the sub account.
87 | ///
88 | long SubaccountId { get; }
89 |
90 | Events Events { get; }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/SparkPost/IMessageEvents.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace SparkPost
4 | {
5 | public interface IMessageEvents
6 | {
7 | Task List();
8 | Task List(object query);
9 | Task SamplesOf(string events);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/SparkPost/IRecipientLists.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace SparkPost
5 | {
6 | public interface IRecipientLists
7 | {
8 | ///
9 | /// Creates a recipient list.
10 | ///
11 | /// The properties of the recipientList to create.
12 | /// The response from the API.
13 | Task Create(RecipientList recipientList);
14 |
15 | ///
16 | /// Retrieves a recipient list.
17 | ///
18 | /// The id of the recipient list to retrieve.
19 | /// The response from the API.
20 | Task Retrieve(string recipientListsId);
21 |
22 | ///
23 | /// Deletes a recipient list.
24 | ///
25 | ///
26 | /// A success or failure.
27 | Task Delete(string id);
28 |
29 | ///
30 | /// Updates a recipient list.
31 | ///
32 | ///
33 | ///
34 | Task Update(RecipientList recipientList);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/SparkPost/IRecipientValidation.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace SparkPost
4 | {
5 | public interface IRecipientValidation
6 | {
7 | Task Create(string emailAddress);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/IRequestMethod.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Threading.Tasks;
3 |
4 | namespace SparkPost
5 | {
6 | public interface IRequestMethod
7 | {
8 | bool CanExecute(Request request);
9 | Task Execute(Request request);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/SparkPost/ISendingDomains.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace SparkPost
4 | {
5 | public interface ISendingDomains
6 | {
7 | Task List();
8 | Task Create(SendingDomain sendingDomain);
9 | Task Update(SendingDomain sendingDomain);
10 | Task Retrieve(string domain);
11 | Task Delete(string domain);
12 | Task Verify(VerifySendingDomain verifySendingDomain);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/SparkPost/ISubaccounts.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace SparkPost
4 | {
5 | public interface ISubaccounts
6 | {
7 | Task List();
8 |
9 | Task Create(SubaccountCreate subaccount);
10 |
11 | Task Update(SubaccountUpdate subaccount);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/SparkPost/ISuppressions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace SparkPost
5 | {
6 | public interface ISuppressions
7 | {
8 | Task List(SuppressionsQuery supppressionsQuery);
9 | Task List(object query = null);
10 | Task Retrieve(string email);
11 | Task CreateOrUpdate(IEnumerable emails);
12 | Task CreateOrUpdate(IEnumerable suppressions);
13 | Task Delete(string email);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SparkPost/ITemplates.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace SparkPost
4 | {
5 | ///
6 | /// Provides access to the templates resource of the SparkPost API.
7 | ///
8 | public interface ITemplates
9 | {
10 | ///
11 | /// Creates an email template.
12 | ///
13 | /// The properties of the template to create.
14 | /// The response from the API.
15 | Task Create(Template template);
16 |
17 | ///
18 | /// Retrieves an email template.
19 | ///
20 | /// The id of the template to retrieve.
21 | /// If true, returns the most recent draft template. If false, returns the most recent published template. If not provided, returns the most recent template version regardless of draft or published.
22 | /// The response from the API.
23 | Task Retrieve(string templateId, bool? draft = null);
24 |
25 | Task List();
26 |
27 | Task Delete(string templateId);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/SparkPost/ITransmissions.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace SparkPost
4 | {
5 | ///
6 | /// Provides access to the transmissions resource of the SparkPost API.
7 | ///
8 | public interface ITransmissions
9 | {
10 | ///
11 | /// Sends an email transmission.
12 | ///
13 | /// The properties of the transmission to send.
14 | /// The response from the API.
15 | Task Send(Transmission transmission);
16 |
17 | ///
18 | /// Retrieves an email transmission.
19 | ///
20 | /// The id of the transmission to retrieve.
21 | /// The response from the API.
22 | Task Retrieve(string transmissionId);
23 |
24 | ///
25 | /// Lists recent email transmissions.
26 | ///
27 | /// The response from the API.
28 | Task List();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/SparkPost/IValueMapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SparkPost
4 | {
5 | public interface IValueMapper
6 | {
7 | bool CanMap(Type propertyType, object value);
8 | object Map(Type propertyType, object value);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/SparkPost/InboundDomain.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class InboundDomain
4 | {
5 | public string Domain { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/SparkPost/InboundDomainResponse.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.Utilities;
2 |
3 | namespace SparkPost
4 | {
5 | public class InboundDomainResponse : Response
6 | {
7 | public InboundDomain InboundDomain { get; set; }
8 |
9 | public static InboundDomainResponse CreateFromResponse(Response response)
10 | {
11 | var result = new InboundDomainResponse();
12 | LeftRight.SetValuesToMatch(result, response);
13 |
14 | var results = Jsonification.DeserializeObject(response.Content).results;
15 |
16 | result.InboundDomain = ListInboundDomainResponse.ConvertToAInboundDomain(results);
17 |
18 | return result;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/SparkPost/InboundDomains.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Threading.Tasks;
3 | using SparkPost.RequestSenders;
4 |
5 | namespace SparkPost
6 | {
7 | public interface IInboundDomains
8 | {
9 | Task List(object query = null);
10 | Task Create(InboundDomain inboundDomain);
11 | Task Retrieve(string domain);
12 | Task Delete(string domain);
13 | }
14 |
15 | public class InboundDomains : IInboundDomains
16 | {
17 | private readonly IClient client;
18 | private readonly IDataMapper dataMapper;
19 | private readonly IRequestSender requestSender;
20 |
21 | public InboundDomains(IClient client, IRequestSender requestSender, IDataMapper dataMapper)
22 | {
23 | this.client = client;
24 | this.requestSender = requestSender;
25 | this.dataMapper = dataMapper;
26 | }
27 |
28 | public async Task List(object query = null)
29 | {
30 | if (query == null)
31 | query = new { };
32 | var request = new Request
33 | {
34 | Url = $"/api/{client.Version}/inbound-domains",
35 | Method = "GET",
36 | Data = query
37 | };
38 |
39 | var response = await requestSender.Send(request);
40 | if (response.StatusCode != HttpStatusCode.OK)
41 | throw new ResponseException(response);
42 |
43 | return ListInboundDomainResponse.CreateFromResponse(response);
44 | }
45 |
46 | public async Task Retrieve(string domain)
47 | {
48 | var request = new Request { Url = $"/api/{client.Version}/inbound-domains/{domain}", Method = "GET" };
49 |
50 | var response = await requestSender.Send(request);
51 | if (response.StatusCode != HttpStatusCode.OK)
52 | throw new ResponseException(response);
53 |
54 | return InboundDomainResponse.CreateFromResponse(response);
55 | }
56 |
57 | public async Task Create(InboundDomain inboundDomain)
58 | {
59 | var request = new Request
60 | {
61 | Url = $"api/{client.Version}/inbound-domains",
62 | Method = "POST",
63 | Data = dataMapper.ToDictionary(inboundDomain)
64 | };
65 |
66 | var response = await requestSender.Send(request);
67 | if (response.StatusCode != HttpStatusCode.OK)
68 | throw new ResponseException(response);
69 |
70 | var createInboundDomainResponse = new Response();
71 | LeftRight.SetValuesToMatch(createInboundDomainResponse, response);
72 | return createInboundDomainResponse;
73 | }
74 |
75 | public async Task Delete(string domain)
76 | {
77 | var request = new Request { Url = $"/api/{client.Version}/inbound-domains/{domain}", Method = "DELETE" };
78 |
79 | var response = await requestSender.Send(request);
80 | return response.StatusCode == HttpStatusCode.OK;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/SparkPost/InlineImage.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class InlineImage : File { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/SparkPost/LeftRight.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 |
3 | namespace SparkPost
4 | {
5 | public static class LeftRight
6 | {
7 | public static void SetValuesToMatch(object left, object right)
8 | {
9 | var leftProperties = left.GetType().GetProperties();
10 | var rightProperties = left.GetType().GetProperties();
11 | foreach (var rightProperty in rightProperties)
12 | {
13 | try
14 | {
15 | var leftProperty = leftProperties.FirstOrDefault(x => x.Name == rightProperty.Name);
16 | leftProperty?.SetValue(left, rightProperty.GetValue(right));
17 | }
18 | catch
19 | {
20 | // ignore
21 | }
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/SparkPost/ListInboundDomainResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using SparkPost.Utilities;
3 |
4 | namespace SparkPost
5 | {
6 | public class ListInboundDomainResponse : Response
7 | {
8 | public IEnumerable InboundDomains { get; set; }
9 |
10 | public static ListInboundDomainResponse CreateFromResponse(Response response)
11 | {
12 | var thisResponse = new ListInboundDomainResponse();
13 |
14 | LeftRight.SetValuesToMatch(thisResponse, response);
15 |
16 | thisResponse.InboundDomains = BuildTheInboundDomainsFrom(response);
17 |
18 | return thisResponse;
19 | }
20 |
21 | private static IEnumerable BuildTheInboundDomainsFrom(Response response)
22 | {
23 | dynamic results = Jsonification.DeserializeObject(response.Content).results;
24 |
25 | var inboundDomains = new List();
26 | foreach (var r in results)
27 | inboundDomains.Add(ConvertToAInboundDomain(r));
28 |
29 | return inboundDomains;
30 | }
31 |
32 | internal static InboundDomain ConvertToAInboundDomain(dynamic item)
33 | {
34 | return new InboundDomain { Domain = item.domain };
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/SparkPost/ListMessageEventsResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SparkPost
4 | {
5 | public class ListMessageEventsResponse : Response
6 | {
7 | public ListMessageEventsResponse()
8 | {
9 | MessageEvents = new MessageEvent[] { };
10 | Links = new PageLink[] { };
11 | }
12 |
13 | public IEnumerable MessageEvents { get; set; }
14 |
15 | public IList Links { get; set; }
16 |
17 | public int TotalCount { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/SparkPost/ListRelayWebhookResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using SparkPost.Utilities;
3 |
4 | namespace SparkPost
5 | {
6 | public class ListRelayWebhookResponse : Response
7 | {
8 | public IEnumerable RelayWebhooks { get; set; }
9 |
10 | public static ListRelayWebhookResponse CreateFromResponse(Response response)
11 | {
12 | var result = new ListRelayWebhookResponse();
13 |
14 | LeftRight.SetValuesToMatch(result, response);
15 |
16 | result.RelayWebhooks = BuildTheRelayWebhooksFrom(response);
17 |
18 | return result;
19 | }
20 |
21 | private static IEnumerable BuildTheRelayWebhooksFrom(Response response)
22 | {
23 | var results = Jsonification.DeserializeObject(response.Content).results;
24 |
25 | var relayWebhooks = new List();
26 | foreach (var r in results)
27 | relayWebhooks.Add(ConvertToARelayWebhook(r));
28 |
29 | return relayWebhooks;
30 | }
31 |
32 | internal static RelayWebhook ConvertToARelayWebhook(dynamic item)
33 | {
34 | return new RelayWebhook
35 | {
36 | Id = item.id,
37 | Name = item.name,
38 | Target = item.target,
39 | AuthToken = item.auth_token,
40 | Match = new RelayWebhookMatch { Protocol = item.match.protocol, Domain = item.match.domain }
41 | };
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/SparkPost/ListSendingDomainResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using SparkPost.Utilities;
3 |
4 | namespace SparkPost
5 | {
6 | public class ListSendingDomainResponse : Response
7 | {
8 | public IEnumerable SendingDomains { get; set; }
9 |
10 | public static ListSendingDomainResponse CreateFromResponse(Response response)
11 | {
12 | var result = new ListSendingDomainResponse();
13 | LeftRight.SetValuesToMatch(result, response);
14 |
15 | var results = Jsonification.DeserializeObject(response.Content).results;
16 | result.SendingDomains = BuildTheSendingDomains(results);
17 | return result;
18 | }
19 |
20 | private static IEnumerable BuildTheSendingDomains(dynamic results)
21 | {
22 | var sendingDomains = new List();
23 | foreach (var r in results)
24 | sendingDomains.Add(SendingDomain.ConvertToSendingDomain(r));
25 | return sendingDomains;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/SparkPost/ListSubaccountResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using SparkPost.Utilities;
4 |
5 | namespace SparkPost
6 | {
7 | public class ListSubaccountResponse : Response
8 | {
9 | public IEnumerable Subaccounts { get; set; }
10 |
11 | public static ListSubaccountResponse CreateFromResponse(Response response)
12 | {
13 | var result = new ListSubaccountResponse();
14 | LeftRight.SetValuesToMatch(result, response);
15 |
16 | var results = Jsonification.DeserializeObject(response.Content).results;
17 | var subaccounts = new List();
18 | foreach (var r in results)
19 | subaccounts.Add(ConvertToSubaccount(r));
20 |
21 | result.Subaccounts = subaccounts;
22 | return result;
23 | }
24 |
25 | private static Subaccount ConvertToSubaccount(dynamic result)
26 | {
27 | return new Subaccount
28 | {
29 | Id = result.id,
30 | Name = result.name,
31 | Status = Enum.Parse(typeof(SubaccountStatus), result.status.ToString(), true),
32 | ComplianceStatus = result.compliance_status
33 | };
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/SparkPost/ListSuppressionResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SparkPost
4 | {
5 | public class ListSuppressionResponse : Response
6 | {
7 | public IEnumerable Suppressions { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/ListTransmissionResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class ListTransmissionResponse : Response { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/SparkPost/ListWebhookResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using SparkPost.Utilities;
3 |
4 | namespace SparkPost
5 | {
6 | public class ListWebhookResponse : Response
7 | {
8 | public IEnumerable Webhooks { get; set; }
9 |
10 | public static ListWebhookResponse CreateFromResponse(Response response)
11 | {
12 | var result = new ListWebhookResponse();
13 | LeftRight.SetValuesToMatch(result, response);
14 |
15 | var results = Jsonification.DeserializeObject(result.Content).results;
16 | var webhooks = new List();
17 | foreach (var r in results)
18 | webhooks.Add(ConvertToAWebhook(r));
19 |
20 | result.Webhooks = webhooks;
21 | return result;
22 | }
23 |
24 | internal static Webhook ConvertToAWebhook(dynamic r)
25 | {
26 | var events = new List();
27 | foreach (var i in r.events)
28 | events.Add(i.ToString());
29 | var webhook = new Webhook
30 | {
31 | Id = r.id,
32 | Name = r.name,
33 | Target = r.target,
34 | Events = events,
35 | AuthType = r.auth_type,
36 | AuthRequestDetails = r.auth_request_details,
37 | AuthCredentials = r.auth_credentials,
38 | AuthToken = r.auth_token,
39 | LastSuccessful = r.last_successful,
40 | LastFailure = r.last_failure
41 | };
42 | return webhook;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/SparkPost/MessageEventSampleResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class MessageEventSampleResponse : Response { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/SparkPost/MessageEventType.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | // Values taken from:
4 | // https://developers.sparkpost.com/api/#/reference/message-events/message-events
5 | // Additional values and descriptions taken from:
6 | // https://support.sparkpost.com/customer/portal/articles/1976204-webhook-event-reference
7 |
8 | public enum MessageEventType
9 | {
10 | ///
11 | /// Undefined/unknown or unable to parse.
12 | ///
13 | Undefined,
14 |
15 | ///
16 | /// delivery
17 | /// Delivery.
18 | /// Remote MTA acknowledged receipt of a message.
19 | ///
20 | Delivery,
21 |
22 | ///
23 | /// injection
24 | /// Injection.
25 | /// Message is received by or injected into SparkPost.
26 | ///
27 | Injection,
28 |
29 | ///
30 | /// bounce
31 | /// Bounce.
32 | /// Remote MTA has permanently rejected a message.
33 | ///
34 | Bounce,
35 |
36 | ///
37 | /// delay
38 | /// Delay.
39 | /// Remote MTA has temporarily rejected a message.
40 | ///
41 | Delay,
42 |
43 | ///
44 | /// policy_rejection
45 | /// Policy Rejection.
46 | /// Due to policy, SparkPost rejected a message or failed to generate a message.
47 | ///
48 | PolicyRejection,
49 |
50 | ///
51 | /// out_of_band
52 | /// Out of Band.
53 | /// Remote MTA initially reported acceptance of a message, but it has since asynchronously reported that the message was not delivered.
54 | ///
55 | OutOfBand,
56 |
57 | ///
58 | /// open
59 | /// Open.
60 | /// Recipient opened a message in a mail client, thus rendering a tracking pixel.
61 | ///
62 | Open,
63 |
64 | ///
65 | /// click
66 | /// Click.
67 | /// Recipient clicked a tracked link in a message, thus prompting a redirect through the SparkPost click-tracking server to the link's destination.
68 | ///
69 | Click,
70 |
71 | ///
72 | /// generation_failure
73 | /// Generation Failure.
74 | /// Message generation failed for an intended recipient.
75 | ///
76 | GenerationFailure,
77 |
78 | ///
79 | /// generation_rejection
80 | /// Generation Rejection.
81 | /// SparkPost rejected message generation due to policy.
82 | ///
83 | GenerationRejection,
84 |
85 | ///
86 | /// spam_complaint
87 | /// Spam Complaint.
88 | /// Message was classified as spam by the recipient.
89 | ///
90 | SpamComplaint,
91 |
92 | ///
93 | /// list_unsubscribe
94 | /// List Unsubscribe.
95 | /// User clicked the 'unsubscribe' button on an email client.
96 | ///
97 | ListUnsubscribe,
98 |
99 | ///
100 | /// link_unsubscribe
101 | /// Link Unsubscribe.
102 | /// User clicked a hyperlink in a received email.
103 | ///
104 | LinkUnsubscribe,
105 |
106 | ///
107 | /// sms_status
108 | /// SMS Status.
109 | /// SMPP/SMS message produced a status log output.
110 | ///
111 | SmsStatus,
112 |
113 | ///
114 | /// relay_injection
115 | /// Relay Injection.
116 | /// Relayed message is received by or injected into SparkPost.
117 | ///
118 | RelayInjection,
119 |
120 | ///
121 | /// relay_rejection
122 | /// Relay Rejection.
123 | /// SparkPost rejected a relayed message or failed to generate a relayed message.
124 | ///
125 | RelayRejection,
126 |
127 | ///
128 | /// relay_delivery
129 | /// Relay Delivery.
130 | /// Remote HTTP Endpoint acknowledged receipt of a relayed message.
131 | ///
132 | RelayDelivery,
133 |
134 | ///
135 | /// relay_tempfail
136 | /// Relay Temporary Failure.
137 | /// Remote HTTP Endpoint has failed to accept a relayed message.
138 | ///
139 | RelayTempfail,
140 |
141 | ///
142 | /// relay_permfail
143 | /// Relay Permanent Failure.
144 | /// Relayed message has reached the maximum retry threshold and will be removed from the system.
145 | ///
146 | RelayPermfail
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/SparkPost/MessageEventsQuery.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.Utilities;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace SparkPost
7 | {
8 | public class MessageEventsQuery
9 | {
10 | public MessageEventsQuery()
11 | {
12 | this.Events = new List();
13 | this.BounceClasses = new List();
14 | this.CampaignIds = new List();
15 | this.FriendlyFroms = new List();
16 | this.MessageIds = new List();
17 | this.Recipients = new List();
18 | this.Subaccounts = new List();
19 | this.TemplateIds = new List();
20 | this.TransmissionIds = new List();
21 | }
22 |
23 | ///
24 | /// bounce_classes : Number : Comma-delimited list of bounce classification codes to search.
25 | /// See Bounce Classification Codes at https://support.sparkpost.com/customer/portal/articles/1929896.
26 | /// Example: 1,10,20.
27 | ///
28 | public IList BounceClasses { get; set; }
29 |
30 | ///
31 | /// campaign_ids : ? : (optional, string, `Example Campaign Name`) ... Comma-delimited list of campaign ID's to search (i.e. campaign_id used during creation of a transmission).
32 | ///
33 | public IList CampaignIds { get; set; }
34 |
35 | ///
36 | /// events : List : Comma-delimited list of event types to search. Defaults to all event types.
37 | /// Example: delivery, injection, bounce, delay, policy_rejection, out_of_band, open, click, generation_failure, generation_rejection, spam_complaint, list_unsubscribe, link_unsubscribe.
38 | ///
39 | public IList Events { get; set; }
40 |
41 | ///
42 | /// friendly_froms : ? : (optional, list, `sender@mail.example.com`) ... Comma-delimited list of friendly_froms to search.
43 | ///
44 | public IList FriendlyFroms { get; set; }
45 |
46 | ///
47 | /// from : Datetime : Datetime in format of YYYY-MM-DDTHH:MM.
48 | /// Example: 2014-07-20T08:00.
49 | /// Default: One hour ago.
50 | ///
51 | public DateTime? From { get; set; }
52 |
53 | ///
54 | /// message_ids : List : Comma-delimited list of message ID's to search.
55 | /// Example: 0e0d94b7-9085-4e3c-ab30-e3f2cd9c273e.
56 | ///
57 | public IList MessageIds { get; set; }
58 |
59 | ///
60 | /// page : number : The results page number to return. Used with per_page for paging through results.
61 | /// Example: 25.
62 | /// Default: 1.
63 | ///
64 | public int? Page { get; set; }
65 |
66 | ///
67 | /// per_page : Number : Number of results to return per page. Must be between 1 and 10,000 (inclusive).
68 | /// Example: 100.
69 | /// Default: 1000.
70 | ///
71 | public int? PerPage { get; set; }
72 |
73 | ///
74 | /// reason : String :Bounce/failure/rejection reason that will be matched using a wildcard(e.g., %reason%).
75 | /// Example: bounce.
76 | ///
77 | public string Reason { get; set; }
78 |
79 | ///
80 | /// recipients : List : Comma-delimited list of recipients to search.
81 | /// Example: recipient @example.com.
82 | ///
83 | public IList Recipients { get; set; }
84 |
85 | ///
86 | /// subaccounts : List : Comma-delimited list of subaccount ID's to search.
87 | /// Example: 101.
88 | ///
89 | public IList Subaccounts { get; set; }
90 |
91 | ///
92 | /// template_ids : List : Comma-delimited list of template ID's to search.
93 | /// Example: templ-1234.
94 | ///
95 | public IList TemplateIds { get; set; }
96 |
97 | ///
98 | /// timezone : String : Standard timezone identification string.
99 | /// Example: America/New_York.
100 | /// Default: UTC.
101 | ///
102 | public string Timezone { get; set; }
103 |
104 | ///
105 | /// to : Datetime : Datetime in format of YYYY-MM-DDTHH:MM.
106 | /// Example: 2014-07-20T09:00.
107 | /// Default: now.
108 | ///
109 | public DateTime? To { get; set; }
110 |
111 | ///
112 | /// transmission_ids : List : Comma-delimited list of transmission ID's to search (i.e. id generated during creation of a transmission).
113 | /// Example: 65832150921904138.
114 | ///
115 | public IList TransmissionIds { get; set; }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/SparkPost/MetricsQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SparkPost
8 | {
9 | public class MetricsQuery
10 | {
11 | public DateTime? From { get; set; }
12 | public DateTime? To { get; set; }
13 | public IList Domains { get; set; }
14 | public IList Campaigns { get; set; }
15 | public IList Templates { get; set; }
16 | public IList SendingIps { get; set; }
17 | public IList IpPools { get; set; }
18 | public IList SendingDomains { get; set; }
19 | public IList Subaccounts { get; set; }
20 | public IList Metrics { get; set; }
21 | public string Timezone { get; set; }
22 | public string Precision { get; set; }
23 |
24 | public MetricsQuery()
25 | {
26 | Domains = new List();
27 | Campaigns = new List();
28 | Templates = new List();
29 | SendingIps = new List();
30 | IpPools = new List();
31 | SendingDomains = new List();
32 | Subaccounts = new List();
33 | Metrics = new List();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/SparkPost/MetricsResourceQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SparkPost
8 | {
9 | public class MetricsResourceQuery
10 | {
11 | ///
12 | /// Only return results containing this string
13 | ///
14 | public string Match { get; set; }
15 |
16 | ///
17 | /// Maximum number of results to return
18 | ///
19 | public int? Limit { get; set; }
20 | public DateTime? From { get; set; }
21 | public DateTime? To { get; set; }
22 |
23 | ///
24 | /// Standard timezone identification string, defaults to UTC
25 | ///
26 | public string Timezone { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/SparkPost/Options.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SparkPost
4 | {
5 | public class Options
6 | {
7 | public DateTimeOffset? StartTime { get; set; }
8 | public bool? OpenTracking { get; set; }
9 | public bool? ClickTracking { get; set; }
10 | public bool? Transactional { get; set; }
11 | public bool? Sandbox { get; set; }
12 | public bool? SkipSuppression { get; set; }
13 | public bool? InlineCss { get; set; }
14 | public string IpPool { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/SparkPost/PageLink.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class PageLink
4 | {
5 | public string Href { get; set; }
6 | public string Type { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/SparkPost/Recipient.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SparkPost
4 | {
5 | public class Recipient
6 | {
7 | public Recipient()
8 | {
9 | Address = new Address();
10 | Tags = new List();
11 | Metadata = new Dictionary();
12 | SubstitutionData = new Dictionary();
13 | }
14 |
15 | public Address Address { get; set; }
16 | public string ReturnPath { get; set; }
17 | public IList Tags { get; set; }
18 | public IDictionary Metadata { get; set; }
19 | public IDictionary SubstitutionData { get; set; }
20 |
21 | public RecipientType Type { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/SparkPost/RecipientList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SparkPost
4 | {
5 | public class RecipientList
6 | {
7 | public RecipientList()
8 | {
9 | Recipients = new List();
10 | Attributes = new Attributes();
11 | }
12 |
13 | public List Recipients { get; set; }
14 |
15 | public string Id { get; set; }
16 |
17 | public string Name { get; set; }
18 |
19 | public string Description { get; set; }
20 |
21 | public Attributes Attributes { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/SparkPost/RecipientLists.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Threading.Tasks;
6 | using Newtonsoft.Json;
7 | using SparkPost.RequestSenders;
8 |
9 | namespace SparkPost
10 | {
11 | public class RecipientLists : IRecipientLists
12 | {
13 | private readonly Client client;
14 | private readonly IRequestSender requestSender;
15 | private readonly DataMapper dataMapper;
16 |
17 | public RecipientLists(Client client, IRequestSender requestSender, DataMapper dataMapper)
18 | {
19 | this.client = client;
20 | this.requestSender = requestSender;
21 | this.dataMapper = dataMapper;
22 | }
23 |
24 | public async Task Retrieve(string recipientListsId)
25 | {
26 | var request = new Request
27 | {
28 | Url = $"api/{client.Version}/recipient-lists/" + recipientListsId + "?show_recipients=true",
29 | Method = "GET",
30 | };
31 |
32 | var response = await requestSender.Send(request);
33 |
34 | if (new[] { HttpStatusCode.OK, HttpStatusCode.NotFound }.Contains(response.StatusCode) == false)
35 | throw new ResponseException(response);
36 |
37 | var recipientListsResponse = new RetrieveRecipientListsResponse()
38 | {
39 | ReasonPhrase = response.ReasonPhrase,
40 | StatusCode = response.StatusCode,
41 | Content = response.Content,
42 | };
43 |
44 | var results = JsonConvert.DeserializeObject(response.Content).results;
45 | if (results.recipients == null)
46 | return recipientListsResponse;
47 |
48 | recipientListsResponse.TotalAcceptedRecipients = results.total_accepted_recipients;
49 |
50 | recipientListsResponse.RecipientList = new RecipientList
51 | {
52 | Id = results.id,
53 | Recipients = RetrieveRecipientListsResponse.CreateFromResponse(response),
54 | Attributes =
55 | results.attributes != null
56 | ? new Attributes { InternalId = results.attributes.internal_id, ListGroupId = results.attributes.list_group_id }
57 | : null,
58 | Description = results.description,
59 | Name = results.name
60 | };
61 |
62 | return recipientListsResponse;
63 | }
64 |
65 | public async Task Delete(string id)
66 | {
67 | var request = new Request { Url = $"/api/{client.Version}/recipient-lists/{id}", Method = "DELETE" };
68 |
69 | var response = await requestSender.Send(request);
70 | return response.StatusCode == HttpStatusCode.NoContent;
71 | }
72 |
73 | public async Task Update(RecipientList recipientList)
74 | {
75 | var request = new Request
76 | {
77 | Url = $"api/{client.Version}/recipient-lists/{recipientList.Id}",
78 | Method = "PUT",
79 | Data = dataMapper.ToDictionary(recipientList)
80 | };
81 |
82 | var response = await requestSender.Send(request);
83 |
84 | if (new[] { HttpStatusCode.OK, HttpStatusCode.NotFound }.Contains(response.StatusCode) == false)
85 | throw new ResponseException(response);
86 |
87 | return new UpdateRecipientListResponse()
88 | {
89 | ReasonPhrase = response.ReasonPhrase,
90 | StatusCode = response.StatusCode,
91 | Content = response.Content,
92 | };
93 | }
94 |
95 | public async Task Create(RecipientList recipientList)
96 | {
97 | var request = new Request
98 | {
99 | Url = $"api/{client.Version}/recipient-lists?num_rcpt_errors=3",
100 | Method = "POST",
101 | Data = dataMapper.ToDictionary(recipientList)
102 | };
103 |
104 | var response = await requestSender.Send(request);
105 |
106 | if (response.StatusCode != HttpStatusCode.OK)
107 | throw new ResponseException(response);
108 |
109 | var results = JsonConvert.DeserializeObject(response.Content).results;
110 | return new SendRecipientListsResponse()
111 | {
112 | Id = results.id,
113 | TotalAcceptedRecipients = results.total_accepted_recipients,
114 | TotalRejectedRecipients = results.total_rejected_recipients,
115 | Name = results.name,
116 | Content = response.Content,
117 | StatusCode = response.StatusCode,
118 | ReasonPhrase = response.ReasonPhrase
119 | };
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/SparkPost/RecipientType.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public enum RecipientType
4 | {
5 | To,
6 | CC,
7 | BCC
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/RecipientValidation.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Threading.Tasks;
3 | using SparkPost.RequestSenders;
4 |
5 | namespace SparkPost
6 | {
7 | public class RecipientValidation : IRecipientValidation
8 | {
9 | private readonly IClient client;
10 | private readonly IRequestSender requestSender;
11 |
12 | public RecipientValidation(IClient client, IRequestSender requestSender)
13 | {
14 | this.client = client;
15 | this.requestSender = requestSender;
16 | }
17 |
18 | public async Task Create(string emailAddress)
19 | {
20 | var request = new Request { Url = $"/api/{client.Version}/recipient-validation/single/{emailAddress}", Method = "GET" };
21 |
22 | var response = await requestSender.Send(request);
23 | if (response.StatusCode != HttpStatusCode.OK)
24 | {
25 | throw new ResponseException(response);
26 | }
27 |
28 | return RetrieveEmailValidationResponse.CreateFromResponse(response);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/SparkPost/RelayWebhook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SparkPost
5 | {
6 | public class RelayWebhook
7 | {
8 | public RelayWebhook()
9 | {
10 | Match = new RelayWebhookMatch();
11 | }
12 |
13 | public string Id { get; set; }
14 | public string Target { get; set; }
15 | public string Name { get; set; }
16 | public string AuthToken { get; set; }
17 | public RelayWebhookMatch Match { get; set; }
18 | }
19 |
20 | public class RelayWebhookMatch
21 | {
22 | public RelayWebhookMatch()
23 | {
24 | Protocol = "SMTP";
25 | }
26 |
27 | public string Protocol { get; set; }
28 | public string Domain { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/SparkPost/RelayWebhooks.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Threading.Tasks;
3 | using SparkPost.RequestSenders;
4 |
5 | namespace SparkPost
6 | {
7 | public interface IRelayWebhooks
8 | {
9 | Task List(object query = null);
10 | Task Create(RelayWebhook webhook);
11 | Task Retrieve(string id);
12 | Task Update(RelayWebhook relayWebhook);
13 | Task Delete(string id);
14 | }
15 |
16 | public class RelayWebhooks : IRelayWebhooks
17 | {
18 | private readonly IClient client;
19 | private readonly IDataMapper dataMapper;
20 | private readonly IRequestSender requestSender;
21 |
22 | public RelayWebhooks(IClient client, IRequestSender requestSender, IDataMapper dataMapper)
23 | {
24 | this.client = client;
25 | this.requestSender = requestSender;
26 | this.dataMapper = dataMapper;
27 | }
28 |
29 | public async Task List(object query = null)
30 | {
31 | if (query == null)
32 | query = new { };
33 | var request = new Request
34 | {
35 | Url = $"/api/{client.Version}/relay-webhooks",
36 | Method = "GET",
37 | Data = query
38 | };
39 |
40 | var response = await requestSender.Send(request);
41 | if (response.StatusCode != HttpStatusCode.OK)
42 | throw new ResponseException(response);
43 |
44 | return ListRelayWebhookResponse.CreateFromResponse(response);
45 | }
46 |
47 | public async Task Retrieve(string id)
48 | {
49 | var request = new Request { Url = $"/api/{client.Version}/relay-webhooks/{id}", Method = "GET" };
50 |
51 | var response = await requestSender.Send(request);
52 | if (response.StatusCode != HttpStatusCode.OK)
53 | throw new ResponseException(response);
54 |
55 | return RetrieveRelayWebhookResponse.CreateFromResponse(response);
56 | }
57 |
58 | public async Task Create(RelayWebhook relayWebhook)
59 | {
60 | var request = new Request
61 | {
62 | Url = $"api/{client.Version}/relay-webhooks",
63 | Method = "POST",
64 | Data = dataMapper.ToDictionary(relayWebhook)
65 | };
66 |
67 | var response = await requestSender.Send(request);
68 | if (response.StatusCode != HttpStatusCode.OK)
69 | throw new ResponseException(response);
70 |
71 | var createWebhookResponse = new Response();
72 | LeftRight.SetValuesToMatch(createWebhookResponse, response);
73 | return createWebhookResponse;
74 | }
75 |
76 | public async Task Update(RelayWebhook relayWebhook)
77 | {
78 | var request = new Request
79 | {
80 | Url = $"api/{client.Version}/relay-webhooks/{relayWebhook.Id}",
81 | Method = "PUT",
82 | Data = dataMapper.ToDictionary(relayWebhook)
83 | };
84 |
85 | var response = await requestSender.Send(request);
86 | if (response.StatusCode != HttpStatusCode.OK)
87 | throw new ResponseException(response);
88 |
89 | var createWebhookResponse = new Response();
90 | LeftRight.SetValuesToMatch(createWebhookResponse, response);
91 | return createWebhookResponse;
92 | }
93 |
94 | public async Task Delete(string id)
95 | {
96 | var request = new Request { Url = $"/api/{client.Version}/relay-webhooks/{id}", Method = "DELETE" };
97 |
98 | var response = await requestSender.Send(request);
99 | return response.StatusCode == HttpStatusCode.OK;
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/SparkPost/Request.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.Utilities;
2 |
3 | namespace SparkPost
4 | {
5 | public class Request
6 | {
7 | public string Url { get; set; }
8 | public object Data { get; set; }
9 | public string Method { get; set; }
10 |
11 | public string ToJson()
12 | {
13 | return Jsonification.SerializeObject(this);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestMethodFinder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Net.Http;
4 | using SparkPost.RequestMethods;
5 |
6 | namespace SparkPost
7 | {
8 | public interface IRequestMethodFinder
9 | {
10 | IRequestMethod FindFor(Request request);
11 | }
12 |
13 | public class RequestMethodFinder : IRequestMethodFinder
14 | {
15 | private readonly HttpClient client;
16 | private readonly IDataMapper dataMapper;
17 |
18 | public RequestMethodFinder(HttpClient client, IDataMapper dataMapper)
19 | {
20 | this.client = client;
21 | this.dataMapper = dataMapper;
22 | }
23 |
24 | public IRequestMethod FindFor(Request request)
25 | {
26 | return new List { new Delete(client), new Post(client), new Put(client), new Get(client, dataMapper) }.First(
27 | x => x.CanExecute(request)
28 | );
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestMethods/Delete.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Threading.Tasks;
3 |
4 | namespace SparkPost.RequestMethods
5 | {
6 | public class Delete : RequestMethod
7 | {
8 | private readonly HttpClient client;
9 |
10 | public Delete(HttpClient client)
11 | {
12 | this.client = client;
13 | }
14 |
15 | public override Task Execute(Request request)
16 | {
17 | return client.DeleteAsync(request.Url);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestMethods/Get.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Http;
7 | using System.Threading.Tasks;
8 | using System.Web;
9 | using SparkPost.Utilities;
10 |
11 | namespace SparkPost.RequestMethods
12 | {
13 | public class Get : RequestMethod
14 | {
15 | private readonly HttpClient client;
16 | private readonly IDataMapper dataMapper;
17 |
18 | public Get(HttpClient client, IDataMapper dataMapper)
19 | {
20 | this.client = client;
21 | this.dataMapper = dataMapper;
22 | }
23 |
24 | public override Task Execute(Request request)
25 | {
26 | return client.GetAsync(
27 | string.Join("?", new[] { request.Url, ConvertToQueryString(request.Data) }.Where(x => string.IsNullOrEmpty(x) == false))
28 | );
29 | }
30 |
31 | private string ConvertToQueryString(object data)
32 | {
33 | if (data == null)
34 | return null;
35 | var original = dataMapper.CatchAll(data);
36 |
37 | var dictionary = new Dictionary();
38 | foreach (var thing in original.Where(x => string.IsNullOrEmpty(x.Value.ToString()) == false))
39 | dictionary[thing.Key] = thing.Value.ToString();
40 |
41 | var values = dictionary.Select(x => WebUtility.UrlEncode(SnakeCase.Convert(x.Key)) + "=" + WebUtility.UrlEncode(x.Value));
42 |
43 | return string.Join("&", values);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestMethods/Post.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using System.Threading.Tasks;
4 |
5 | namespace SparkPost.RequestMethods
6 | {
7 | public class Post : PutAndPostAreTheSame
8 | {
9 | public Post(HttpClient client) : base(client) { }
10 |
11 | public override Task Execute(string url, StringContent stringContent)
12 | {
13 | return Client.PostAsync(url, stringContent);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestMethods/Put.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Threading.Tasks;
3 |
4 | namespace SparkPost.RequestMethods
5 | {
6 | public class Put : PutAndPostAreTheSame
7 | {
8 | public Put(HttpClient client) : base(client) { }
9 |
10 | public override Task Execute(string url, StringContent stringContent)
11 | {
12 | return Client.PutAsync(url, stringContent);
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestMethods/PutAndPostAreTheSame.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Text;
3 | using System.Threading.Tasks;
4 | using SparkPost.Utilities;
5 |
6 | namespace SparkPost.RequestMethods
7 | {
8 | public abstract class PutAndPostAreTheSame : RequestMethod
9 | {
10 | protected readonly HttpClient Client;
11 |
12 | protected PutAndPostAreTheSame(HttpClient client)
13 | {
14 | Client = client;
15 | }
16 |
17 | public override Task Execute(Request request)
18 | {
19 | return Execute(request.Url, ContentFrom(request));
20 | }
21 |
22 | public abstract Task Execute(string url, StringContent stringContent);
23 |
24 | private static StringContent ContentFrom(Request request)
25 | {
26 | return new StringContent(SerializeObject(request.Data), Encoding.UTF8, "application/json");
27 | }
28 |
29 | private static string SerializeObject(object data)
30 | {
31 | return Jsonification.SerializeObject(data);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestMethods/RequestMethod.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Threading.Tasks;
3 |
4 | namespace SparkPost.RequestMethods
5 | {
6 | public abstract class RequestMethod : IRequestMethod
7 | {
8 | public bool CanExecute(Request request)
9 | {
10 | return (request.Method ?? "").ToLower().StartsWith(GetType().Name.ToLower());
11 | }
12 |
13 | public abstract Task Execute(Request request);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SparkPost/RequestSenders/RequestSender.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Net.Http;
4 | using System.Threading.Tasks;
5 |
6 | namespace SparkPost.RequestSenders
7 | {
8 | public interface IRequestSender
9 | {
10 | Task Send(Request request);
11 | }
12 |
13 | public class RequestSender : IRequestSender
14 | {
15 | private readonly IClient client;
16 | private readonly IDataMapper dataMapper;
17 |
18 | public RequestSender(IClient client, IDataMapper dataMapper)
19 | {
20 | this.client = client;
21 | this.dataMapper = dataMapper;
22 | }
23 |
24 | public virtual async Task Send(Request request)
25 | {
26 | using (var httpClient = client.CustomSettings.CreateANewHttpClient())
27 | {
28 | httpClient.BaseAddress = new Uri(client.ApiHost);
29 | httpClient.DefaultRequestHeaders.Add("Authorization", client.ApiKey);
30 |
31 | SetTheUserAgentIfItIsProvided(httpClient);
32 |
33 | if (client.SubaccountId != 0)
34 | httpClient.DefaultRequestHeaders.Add("X-MSYS-SUBACCOUNT", client.SubaccountId.ToString(CultureInfo.InvariantCulture));
35 |
36 | var result = await GetTheResponse(request, httpClient);
37 |
38 | return new Response
39 | {
40 | StatusCode = result.StatusCode,
41 | ReasonPhrase = result.ReasonPhrase,
42 | Content = await result.Content.ReadAsStringAsync()
43 | };
44 | }
45 | }
46 |
47 | private void SetTheUserAgentIfItIsProvided(HttpClient httpClient)
48 | {
49 | if (string.IsNullOrEmpty(client.CustomSettings.UserAgent) == false)
50 | httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", client.CustomSettings.UserAgent);
51 | }
52 |
53 | protected virtual async Task GetTheResponse(Request request, HttpClient httpClient)
54 | {
55 | return await new RequestMethodFinder(httpClient, dataMapper).FindFor(request).Execute(request);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/SparkPost/Response.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 |
3 | namespace SparkPost
4 | {
5 | public class Response
6 | {
7 | public HttpStatusCode StatusCode { get; set; }
8 | public string ReasonPhrase { get; set; }
9 | public string Content { get; set; }
10 |
11 | protected void SetFrom(Response source)
12 | {
13 | this.ReasonPhrase = source.ReasonPhrase;
14 | this.StatusCode = source.StatusCode;
15 | this.Content = source.Content;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/SparkPost/ResponseException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SparkPost
4 | {
5 | public class ResponseException : Exception
6 | {
7 | public ResponseException(Response response)
8 | : base(string.Format("Response: {0} {1}. Content: {2}.", ((int)response.StatusCode).ToString(), response.ReasonPhrase, response.Content))
9 | {
10 | this.Response = response;
11 | }
12 |
13 | public Response Response { get; private set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SparkPost/RetrieveEmailValidationResponse.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.Utilities;
2 |
3 | namespace SparkPost
4 | {
5 | public class RetrieveEmailValidationResponse : Response
6 | {
7 | public static EmailValidationResponse CreateFromResponse(Response response)
8 | {
9 | var jsonData = Jsonification.DeserializeObject(response.Content).results;
10 | return EmailValidationResponse.ConvertToResponse(jsonData);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/SparkPost/RetrieveRecipientListsResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Newtonsoft.Json;
4 |
5 | namespace SparkPost
6 | {
7 | public class RetrieveRecipientListsResponse : Response
8 | {
9 | public int TotalAcceptedRecipients { get; set; }
10 |
11 | public RecipientList RecipientList { get; set; }
12 |
13 | public static List CreateFromResponse(Response response)
14 | {
15 | var result = new List();
16 |
17 | var results = JsonConvert.DeserializeObject(response.Content).results;
18 |
19 | foreach (var r in results.recipients)
20 | result.Add(ConvertToRecipient(r));
21 |
22 | return result;
23 | }
24 |
25 | internal static Recipient ConvertToRecipient(dynamic item)
26 | {
27 | return new Recipient
28 | {
29 | Address = new Address { Email = item.address.email, Name = item.address.name },
30 | ReturnPath = item.return_path,
31 | Metadata = ConvertToADictionary(item.metadata),
32 | SubstitutionData = ConvertToADictionary(item.substitution_data)
33 | };
34 | }
35 |
36 | private static dynamic ConvertToADictionary(dynamic @object)
37 | {
38 | return JsonConvert.DeserializeObject>(JsonConvert.SerializeObject(@object));
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/SparkPost/RetrieveRelayWebhookResponse.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.Utilities;
2 |
3 | namespace SparkPost
4 | {
5 | public class RetrieveRelayWebhookResponse : Response
6 | {
7 | public RelayWebhook RelayWebhook { get; set; }
8 |
9 | public static RetrieveRelayWebhookResponse CreateFromResponse(Response response)
10 | {
11 | var result = new RetrieveRelayWebhookResponse();
12 | LeftRight.SetValuesToMatch(result, response);
13 |
14 | var results = Jsonification.DeserializeObject(response.Content).results;
15 |
16 | result.RelayWebhook = ListRelayWebhookResponse.ConvertToARelayWebhook(results);
17 |
18 | return result;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/SparkPost/RetrieveTemplateResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SparkPost
8 | {
9 | public class RetrieveTemplateResponse : Response
10 | {
11 | public RetrieveTemplateResponse()
12 | {
13 | Options = new TemplateOptions();
14 | TemplateContent = new TemplateContent();
15 | }
16 |
17 | public string Id { get; set; }
18 | public string Name { get; set; }
19 | public string Description { get; set; }
20 | public bool Published { get; set; }
21 | public DateTime LastUpdateTime { get; set; }
22 | public DateTime? LastUse { get; set; }
23 | public TemplateOptions Options { get; set; }
24 | public TemplateContent TemplateContent { get; set; }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/SparkPost/RetrieveTemplatesResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SparkPost
5 | {
6 | public class RetrieveTemplatesResponse : Response
7 | {
8 | public RetrieveTemplatesResponse()
9 | {
10 | Templates = new List();
11 | }
12 |
13 | public List Templates { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SparkPost/RetrieveTransmissionResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SparkPost
4 | {
5 | public class RetrieveTransmissionResponse : Response
6 | {
7 | public string Id { get; set; }
8 | public string Description { get; set; }
9 | public DateTime? GenerationEndTime { get; set; }
10 | public int RecipientListTotalChunks { get; set; }
11 | public int RecipientListTotalSize { get; set; }
12 | public int NumberRecipients { get; set; }
13 | public int NumberGenerated { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SparkPost/RetrieveWebhookResponse.cs:
--------------------------------------------------------------------------------
1 | using SparkPost.Utilities;
2 |
3 | namespace SparkPost
4 | {
5 | public class RetrieveWebhookResponse : Response
6 | {
7 | public Webhook Webhook { get; set; }
8 |
9 | public static RetrieveWebhookResponse CreateFromResponse(Response response)
10 | {
11 | var result = new RetrieveWebhookResponse();
12 | LeftRight.SetValuesToMatch(result, response);
13 |
14 | var results = Jsonification.DeserializeObject(response.Content).results;
15 |
16 | result.Webhook = ListWebhookResponse.ConvertToAWebhook(results);
17 |
18 | return result;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/SparkPost/SendRecipientListsResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class SendRecipientListsResponse : Response
4 | {
5 | public string Id { get; set; }
6 | public int TotalAcceptedRecipients { get; set; }
7 | public int TotalRejectedRecipients { get; set; }
8 | public string Name { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/SparkPost/SendTransmissionResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class SendTransmissionResponse : Response
4 | {
5 | public string Id { get; set; }
6 | public int TotalAcceptedRecipients { get; set; }
7 | public int TotalRejectedRecipients { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/SendingDomain.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class SendingDomain
4 | {
5 | public string Domain { get; set; }
6 |
7 | public string TrackingDomain { get; set; }
8 |
9 | public SendingDomainStatus Status { get; set; }
10 |
11 | public Dkim Dkim { get; set; }
12 |
13 | public bool GenerateDkim { get; set; }
14 |
15 | public long DkimKeyLength { get; set; }
16 |
17 | public bool SharedWithSubAccounts { get; set; }
18 |
19 | ///
20 | /// Convert json result form Sparkpost API to SendingDomain.
21 | ///
22 | /// Json result form Sparkpost API.
23 | ///
24 | public static SendingDomain ConvertToSendingDomain(dynamic result)
25 | {
26 | return result != null
27 | ? new SendingDomain
28 | {
29 | Domain = result.domain,
30 | TrackingDomain = result.tracking_domain,
31 | Status = SendingDomainStatus.ConvertToSendingDomainStatus(result.status),
32 | Dkim = SparkPost.Dkim.ConvertToDkim(result.dkim),
33 | GenerateDkim = result.generate_dkim ?? false,
34 | DkimKeyLength = result.dkim_key_length ?? 0,
35 | SharedWithSubAccounts = result.shared_with_subaccounts ?? false
36 | }
37 | : null;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/SparkPost/SendingDomainStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SparkPost
4 | {
5 | public class SendingDomainStatus
6 | {
7 | public bool OwnershipVerified { get; set; }
8 |
9 | public DkimStatus DkimStatus { get; set; }
10 |
11 | public SpfStatus SpfStatus { get; set; }
12 |
13 | public AbuseAtStatus AbuseAtStatus { get; set; }
14 |
15 | public PostmasterAtStatus PostmasterAtStatus { get; set; }
16 |
17 | public ComplianceStatus ComplianceStatus { get; set; }
18 |
19 | ///
20 | /// Convert json result form Sparkpost API to SendingDomainStatus.
21 | ///
22 | /// Json result form Sparkpost API.
23 | ///
24 | public static SendingDomainStatus ConvertToSendingDomainStatus(dynamic result)
25 | {
26 | if (result == null)
27 | return null;
28 | return new SendingDomainStatus
29 | {
30 | OwnershipVerified = result.ownership_verified ?? false,
31 | DkimStatus = Enum.Parse(typeof(DkimStatus), (result.dkim_status ?? DkimStatus.Unknowed).ToString(), true),
32 | SpfStatus = Enum.Parse(typeof(SpfStatus), (result.spf_status ?? SpfStatus.Unknowed).ToString(), true),
33 | AbuseAtStatus = Enum.Parse(typeof(AbuseAtStatus), (result.abuse_at_status ?? AbuseAtStatus.Unknowed).ToString(), true),
34 | PostmasterAtStatus = Enum.Parse(
35 | typeof(PostmasterAtStatus),
36 | (result.postmaster_at_status ?? PostmasterAtStatus.Unknowed).ToString(),
37 | true
38 | ),
39 | ComplianceStatus = Enum.Parse(typeof(ComplianceStatus), (result.compliance_status ?? ComplianceStatus.Unknowed).ToString(), true)
40 | };
41 | }
42 | }
43 |
44 | public enum DkimStatus
45 | {
46 | Unverified,
47 | Pending,
48 | Invalid,
49 | Valid,
50 | Unknowed
51 | }
52 |
53 | public enum SpfStatus
54 | {
55 | Unverified,
56 | Pending,
57 | Invalid,
58 | Valid,
59 | Unknowed
60 | }
61 |
62 | public enum AbuseAtStatus
63 | {
64 | Unverified,
65 | Pending,
66 | Invalid,
67 | Valid,
68 | Unknowed
69 | }
70 |
71 | public enum PostmasterAtStatus
72 | {
73 | Unverified,
74 | Pending,
75 | Invalid,
76 | Valid,
77 | Unknowed
78 | }
79 |
80 | public enum ComplianceStatus
81 | {
82 | Pending,
83 | Valid,
84 | Unknowed
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/SparkPost/SparkPost.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | SparkPost
4 | SparkPost
5 | SparkPost
6 | SparkPost API
7 | Copyright 2022
8 | 2.0.2
9 | 2.0.2
10 | 2.0.2
11 | Darren Cauthon; Adam Hathcock
12 | https://www.sparkpost.com/sites/default/files/attachments/SparkPost_Logo_2-Color_Gray-Orange_RGB.svg
13 | SparkPost
14 | https://github.com/darrencauthon/csharp-sparkpost/blob/master/LICENSE.md
15 | https://github.com/SparkPost/csharp-sparkpost
16 | LICENSE.md
17 | Added support to pass a user-agent.
18 | email
19 | netstandard2.0
20 | 10
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | LICENSE.md
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/SparkPost/Subaccount.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class Subaccount
4 | {
5 | public long Id { get; set; }
6 | public string Name { get; set; }
7 | public SubaccountStatus Status { get; set; }
8 | public string IpPool { get; set; }
9 | public string ComplianceStatus { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/SparkPost/SubaccountCreate.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class SubaccountCreate
4 | {
5 | public string Name { get; set; }
6 | public string KeyLabel { get; set; }
7 | public string[] KeyGrants { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/SubaccountStatus.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public enum SubaccountStatus
4 | {
5 | Active,
6 | Suspended,
7 | Terminated
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/SubaccountUpdate.cs:
--------------------------------------------------------------------------------
1 | namespace SparkPost
2 | {
3 | public class SubaccountUpdate
4 | {
5 | public long Id { get; set; }
6 | public string Name { get; set; }
7 | public SubaccountStatus Status { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SparkPost/Subaccounts.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Threading.Tasks;
3 | using SparkPost.RequestSenders;
4 | using SparkPost.Utilities;
5 |
6 | namespace SparkPost
7 | {
8 | public class Subaccounts : ISubaccounts
9 | {
10 | private readonly IClient client;
11 | private readonly IRequestSender requestSender;
12 | private readonly IDataMapper dataMapper;
13 |
14 | public Subaccounts(IClient client, IRequestSender requestSender, IDataMapper dataMapper)
15 | {
16 | this.client = client;
17 | this.requestSender = requestSender;
18 | this.dataMapper = dataMapper;
19 | }
20 |
21 | public async Task List()
22 | {
23 | var request = new Request { Url = $"/api/{client.Version}/subaccounts", Method = "GET" };
24 |
25 | var response = await requestSender.Send(request);
26 | if (response.StatusCode != HttpStatusCode.OK)
27 | throw new ResponseException(response);
28 |
29 | return ListSubaccountResponse.CreateFromResponse(response);
30 | }
31 |
32 | public async Task Create(SubaccountCreate subaccount)
33 | {
34 | var request = new Request
35 | {
36 | Url = $"api/{client.Version}/subaccounts",
37 | Method = "POST",
38 | Data = new { name = subaccount.Name, key_label = subaccount.KeyLabel, key_grants = subaccount.KeyGrants }
39 | };
40 |
41 | var response = await requestSender.Send(request);
42 | if (response.StatusCode != HttpStatusCode.OK)
43 | throw new ResponseException(response);
44 |
45 | var results = Jsonification.DeserializeObject(response.Content).results;
46 |
47 | return new CreateSubaccountResponse
48 | {
49 | ReasonPhrase = response.ReasonPhrase,
50 | StatusCode = response.StatusCode,
51 | Content = response.Content,
52 | Key = results.key,
53 | Label = results.label,
54 | ShortKey = results.short_key,
55 | SubaccountId = results.subaccount_id
56 | };
57 | }
58 |
59 | public async Task Update(SubaccountUpdate subaccount)
60 | {
61 | var request = new Request
62 | {
63 | Url = $"api/{client.Version}/subaccounts/{subaccount.Id}",
64 | Method = "PUT JSON",
65 | Data = new { name = subaccount.Name, status = subaccount.Status.ToString().ToLowerInvariant() }
66 | };
67 |
68 | var response = await requestSender.Send(request);
69 | if (response.StatusCode != HttpStatusCode.OK)
70 | throw new ResponseException(response);
71 |
72 | var results = Jsonification.DeserializeObject(response.Content).results;
73 |
74 | return new UpdateSubaccountResponse
75 | {
76 | ReasonPhrase = response.ReasonPhrase,
77 | StatusCode = response.StatusCode,
78 | Content = response.Content
79 | };
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/SparkPost/Suppression.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SparkPost
4 | {
5 | public class Suppression
6 | {
7 | public bool Transactional { get; set; }
8 | public bool NonTransactional { get; set; }
9 | public string Description { get; set; }
10 | public string Email { get; set; }
11 | public string Source { get; set; }
12 | public DateTime? Created { get; set; }
13 | public DateTime? Updated { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SparkPost/Suppressions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Net;
4 | using System.Threading.Tasks;
5 | using System.Web;
6 | using SparkPost.RequestSenders;
7 | using SparkPost.Utilities;
8 |
9 | namespace SparkPost
10 | {
11 | public class Suppressions : ISuppressions
12 | {
13 | private readonly IClient client;
14 | private readonly IRequestSender requestSender;
15 | private readonly IDataMapper dataMapper;
16 |
17 | public Suppressions(IClient client, IRequestSender requestSender, IDataMapper dataMapper)
18 | {
19 | this.client = client;
20 | this.requestSender = requestSender;
21 | this.dataMapper = dataMapper;
22 | }
23 |
24 | public async Task List(SuppressionsQuery supppressionsQuery)
25 | {
26 | return await List(supppressionsQuery as object);
27 | }
28 |
29 | public async Task