diff --git a/src/Sinch/Core/UrlResolver.cs b/src/Sinch/Core/UrlResolver.cs
index 4fe03cc..c8dd677 100644
--- a/src/Sinch/Core/UrlResolver.cs
+++ b/src/Sinch/Core/UrlResolver.cs
@@ -1,5 +1,6 @@
using System;
using Sinch.Conversation;
+using Sinch.Mailgun;
using Sinch.SMS;
using Sinch.Voice;
@@ -83,5 +84,26 @@ public Uri ResolveSmsServicePlanIdUrl(SmsServicePlanIdRegion smsServicePlanIdReg
return new Uri(string.Format(smsApiServicePlanIdUrlTemplate,
smsServicePlanIdRegion.Value.ToLowerInvariant()));
}
+
+ public Uri ResolveMailgunUrl(MailgunRegion mailgunRegion)
+ {
+ if (!string.IsNullOrEmpty(_apiUrlOverrides?.MailgunUrl)) return new Uri(_apiUrlOverrides.MailgunUrl);
+
+ string? mailgunUrl;
+ switch (mailgunRegion)
+ {
+ case MailgunRegion.Us:
+ mailgunUrl = "https://api.mailgun.net";
+ break;
+ case MailgunRegion.Eu:
+ mailgunUrl = "https://api.eu.mailgun.net";
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(mailgunRegion), mailgunRegion,
+ "Unexpected enum value.");
+ }
+
+ return new Uri(mailgunUrl);
+ }
}
}
diff --git a/src/Sinch/Mailgun/MailgunRegion.cs b/src/Sinch/Mailgun/MailgunRegion.cs
new file mode 100644
index 0000000..b5ac210
--- /dev/null
+++ b/src/Sinch/Mailgun/MailgunRegion.cs
@@ -0,0 +1,18 @@
+namespace Sinch.Mailgun
+{
+ ///
+ /// Mailgun allows the ability to send and receive email in both US and EU regions.
+ /// Be sure to use the appropriate region on which you have created your domain.
+ ///
+ public enum MailgunRegion
+ {
+ ///
+ /// United States region
+ ///
+ Us,
+ ///
+ /// Europe region
+ ///
+ Eu
+ }
+}
diff --git a/src/Sinch/Mailgun/SinchMailgunClient.cs b/src/Sinch/Mailgun/SinchMailgunClient.cs
new file mode 100644
index 0000000..874a00a
--- /dev/null
+++ b/src/Sinch/Mailgun/SinchMailgunClient.cs
@@ -0,0 +1,23 @@
+using System;
+using Sinch.Core;
+using Sinch.Logger;
+
+namespace Sinch.Mailgun
+{
+ ///
+ /// The Mailgun API is part of the Sinch family and enables you to send, track, and receive email effortlessly.
+ ///
+ public interface ISinchMailgunClient
+ {
+ // TBD: add domains
+ }
+
+ ///
+ internal class SinchMailgunClient : ISinchMailgunClient
+ {
+ public SinchMailgunClient(Uri baseUrl, Http http, LoggerFactory? loggerFactory = null)
+ {
+ // TBD: implement domains
+ }
+ }
+}
diff --git a/src/Sinch/SinchClient.cs b/src/Sinch/SinchClient.cs
index c3dc7ba..7bb6e81 100644
--- a/src/Sinch/SinchClient.cs
+++ b/src/Sinch/SinchClient.cs
@@ -7,6 +7,7 @@
using Sinch.Conversation;
using Sinch.Core;
using Sinch.Logger;
+using Sinch.Mailgun;
using Sinch.Numbers;
using Sinch.SMS;
using Sinch.Verification;
@@ -111,6 +112,17 @@ public ISinchVerificationClient Verification(string appKey, string appSecret,
/// See . Defaults to
///
public ISinchVoiceClient Voice(string appKey, string appSecret, VoiceRegion? voiceRegion = null);
+
+ ///
+ /// APIs are at the heart of Mailgun.
+ /// Our goal is to provide developers worldwide with an accessible and straightforward way to send,
+ /// receive, and track emails effortlessly.
+ ///
+ /// When you sign up for Mailgun, a primary account API key is generated.
+ /// This key allows you to perform all CRUD operations via our various API endpoints and for any of your sending domains.
+ ///
+ ///
+ public ISinchMailgunClient Mailgun(string apiKey, MailgunRegion region);
}
public class SinchClient : ISinchClient
@@ -131,6 +143,32 @@ public class SinchClient : ISinchClient
private readonly ILoggerAdapter? _logger;
private readonly UrlResolver _urlResolver;
+ ///
+ /// Initialize a new without providing common credentials.
+ /// Intended to be used for APIs which requires their own credentials:
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// If you plan to use other APIs or not sure about what API you are planning to use, consider using main constructor
+ ///
+ ///
+ ///
+ /// var mailgunClient = new SinchClient().Mailgun("apikey", MailgunRegion.Eu);
+ ///
+ ///
+ ///
+ /// Optional. See:
+ public SinchClient(Action? options = default) : this(null, null, null, options)
+ {
+ }
///
/// Initialize a new
@@ -274,6 +312,22 @@ public ISinchVoiceClient Voice(string appKey, string appSecret,
_urlResolver.ResolveVoiceApplicationManagementUrl());
}
+ ///
+ public ISinchMailgunClient Mailgun(string apiKey, MailgunRegion region)
+ {
+ if (string.IsNullOrEmpty(apiKey))
+ {
+ throw new ArgumentNullException(nameof(apiKey), "apiKey shouldn't be null or empty");
+ }
+
+ var baseUrl = _urlResolver.ResolveMailgunUrl(region);
+ var mailgunAuth = new BasicAuth(appKey: "api", appSecret: apiKey);
+ // NOTE: jsonNamingPolicy will not play a role here as property naming of mailgun is inconsistent
+ // meaning, all lifting will be done through JsonPropertyNamingAttribute
+ var http = new Http(mailgunAuth, _httpClient, _loggerFactory?.Create(), JsonNamingPolicy.CamelCase);
+ return new SinchMailgunClient(baseUrl, http, _loggerFactory);
+ }
+
private void ValidateCommonCredentials()
{
var exceptions = new List();
diff --git a/src/Sinch/SinchOptions.cs b/src/Sinch/SinchOptions.cs
index 5a49124..eb90c25 100644
--- a/src/Sinch/SinchOptions.cs
+++ b/src/Sinch/SinchOptions.cs
@@ -137,5 +137,10 @@ public sealed class ApiUrlOverrides
/// Overrides Numbers api base url
///
public string? NumbersUrl { get; init; }
+
+ ///
+ /// Overrides Mailgun api base url
+ ///
+ public string? MailgunUrl { get; init; }
}
}
diff --git a/tests/Sinch.Tests/Core/UrlResolverTests.cs b/tests/Sinch.Tests/Core/UrlResolverTests.cs
index 203b161..fec49e0 100644
--- a/tests/Sinch.Tests/Core/UrlResolverTests.cs
+++ b/tests/Sinch.Tests/Core/UrlResolverTests.cs
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using FluentAssertions;
using Sinch.Conversation;
using Sinch.Core;
+using Sinch.Mailgun;
using Sinch.SMS;
using Sinch.Voice;
using Xunit;
@@ -306,7 +308,8 @@ public void ResolveSmsUrl(SmsRegion smsRegion, ApiUrlOverrides apiUrlOverrides)
[Theory]
[MemberData(nameof(SmsServicePlanIdUrlData))]
- public void ResolveSmsServicePlanIdUrl(SmsServicePlanIdRegion smsServicePlanIdRegion, ApiUrlOverrides apiUrlOverrides)
+ public void ResolveSmsServicePlanIdUrl(SmsServicePlanIdRegion smsServicePlanIdRegion,
+ ApiUrlOverrides apiUrlOverrides)
{
var smsUrl = new UrlResolver(apiUrlOverrides).ResolveSmsServicePlanIdUrl(smsServicePlanIdRegion);
var expectedUrl = string.IsNullOrEmpty(apiUrlOverrides?.SmsUrl)
@@ -314,5 +317,50 @@ public void ResolveSmsServicePlanIdUrl(SmsServicePlanIdRegion smsServicePlanIdRe
: new Uri(apiUrlOverrides.SmsUrl);
smsUrl.Should().BeEquivalentTo(expectedUrl);
}
+
+ public record ResolveMailgunUrlTestData(
+ string TestName,
+ MailgunRegion Region,
+ ApiUrlOverrides ApiUrlOverrides,
+ string ExpectedUrl)
+ {
+ private static readonly ResolveMailgunUrlTestData[] TestCases =
+ {
+ new("Default US Mailgun address", MailgunRegion.Us, null, "https://api.mailgun.net"),
+ new("Default EU Mailgun address", MailgunRegion.Eu, null, "https://api.eu.mailgun.net"),
+ new("Default EU region even if override set but null", MailgunRegion.Eu, new ApiUrlOverrides()
+ {
+ MailgunUrl = null
+ }, "https://api.eu.mailgun.net"),
+ new("Override url", MailgunRegion.Eu, new ApiUrlOverrides()
+ {
+ MailgunUrl = "https://my-mailgun-proxy.net"
+ }, "https://my-mailgun-proxy.net"),
+ };
+
+ public static IEnumerable