mirror of
https://github.com/bitwarden/server.git
synced 2025-04-09 07:08:15 -05:00
amazon ses mail delivery service
This commit is contained in:
parent
8d54442173
commit
7e920b955c
@ -21,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"mail": {
|
"mail": {
|
||||||
"sendGridApiKey": "SECRET",
|
"sendGridApiKey": "SECRET",
|
||||||
|
"amazonConfigSetName": "Email",
|
||||||
"replyToEmail": "hello@bitwarden.com"
|
"replyToEmail": "hello@bitwarden.com"
|
||||||
},
|
},
|
||||||
"identityServer": {
|
"identityServer": {
|
||||||
@ -42,6 +43,11 @@
|
|||||||
"notificationHub": {
|
"notificationHub": {
|
||||||
"connectionString": "SECRET",
|
"connectionString": "SECRET",
|
||||||
"hubName": "SECRET"
|
"hubName": "SECRET"
|
||||||
|
},
|
||||||
|
"amazon": {
|
||||||
|
"accessKeyId": "SECRET",
|
||||||
|
"accessKeySecret": "SECRET",
|
||||||
|
"region": "SECRET"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"adminSettings": {
|
"adminSettings": {
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"mail": {
|
"mail": {
|
||||||
"sendGridApiKey": "SECRET",
|
"sendGridApiKey": "SECRET",
|
||||||
|
"amazonConfigSetName": "Email",
|
||||||
"replyToEmail": "hello@bitwarden.com"
|
"replyToEmail": "hello@bitwarden.com"
|
||||||
},
|
},
|
||||||
"identityServer": {
|
"identityServer": {
|
||||||
@ -67,6 +68,11 @@
|
|||||||
"production": false,
|
"production": false,
|
||||||
"base58Secret": "SECRET",
|
"base58Secret": "SECRET",
|
||||||
"notificationUrl": "https://bitwarden.com/SECRET"
|
"notificationUrl": "https://bitwarden.com/SECRET"
|
||||||
|
},
|
||||||
|
"amazon": {
|
||||||
|
"accessKeyId": "SECRET",
|
||||||
|
"accessKeySecret": "SECRET",
|
||||||
|
"region": "SECRET"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"IpRateLimitOptions": {
|
"IpRateLimitOptions": {
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"mail": {
|
"mail": {
|
||||||
"sendGridApiKey": "SECRET",
|
"sendGridApiKey": "SECRET",
|
||||||
|
"amazonConfigSetName": "Email",
|
||||||
"replyToEmail": "hello@bitwarden.com"
|
"replyToEmail": "hello@bitwarden.com"
|
||||||
},
|
},
|
||||||
"identityServer": {
|
"identityServer": {
|
||||||
@ -56,6 +57,11 @@
|
|||||||
"production": false,
|
"production": false,
|
||||||
"base58Secret": "SECRET",
|
"base58Secret": "SECRET",
|
||||||
"notificationUrl": "https://bitwarden.com/SECRET"
|
"notificationUrl": "https://bitwarden.com/SECRET"
|
||||||
|
},
|
||||||
|
"amazon": {
|
||||||
|
"accessKeyId": "SECRET",
|
||||||
|
"accessKeySecret": "SECRET",
|
||||||
|
"region": "SECRET"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"billingSettings": {
|
"billingSettings": {
|
||||||
|
@ -108,6 +108,7 @@ namespace Bit.Core
|
|||||||
{
|
{
|
||||||
public string ReplyToEmail { get; set; }
|
public string ReplyToEmail { get; set; }
|
||||||
public string SendGridApiKey { get; set; }
|
public string SendGridApiKey { get; set; }
|
||||||
|
public string AmazonConfigSetName { get; set; }
|
||||||
public SmtpSettings Smtp { get; set; } = new SmtpSettings();
|
public SmtpSettings Smtp { get; set; } = new SmtpSettings();
|
||||||
|
|
||||||
public class SmtpSettings
|
public class SmtpSettings
|
||||||
|
@ -9,6 +9,7 @@ namespace Bit.Core.Models.Mail
|
|||||||
public IEnumerable<string> BccEmails { get; set; }
|
public IEnumerable<string> BccEmails { get; set; }
|
||||||
public string HtmlContent { get; set; }
|
public string HtmlContent { get; set; }
|
||||||
public string TextContent { get; set; }
|
public string TextContent { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
public IDictionary<string, object> MetaData { get; set; }
|
public IDictionary<string, object> MetaData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ namespace Bit.Core.Services
|
|||||||
private readonly AmazonSimpleEmailServiceClient _client;
|
private readonly AmazonSimpleEmailServiceClient _client;
|
||||||
private readonly string _source;
|
private readonly string _source;
|
||||||
private readonly string _senderTag;
|
private readonly string _senderTag;
|
||||||
|
private readonly string _configSetName;
|
||||||
|
|
||||||
public AmazonSesMailDeliveryService(
|
public AmazonSesMailDeliveryService(
|
||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
@ -44,7 +45,11 @@ namespace Bit.Core.Services
|
|||||||
_client = new AmazonSimpleEmailServiceClient(globalSettings.Amazon.AccessKeyId,
|
_client = new AmazonSimpleEmailServiceClient(globalSettings.Amazon.AccessKeyId,
|
||||||
globalSettings.Amazon.AccessKeySecret, RegionEndpoint.GetBySystemName(globalSettings.Amazon.Region));
|
globalSettings.Amazon.AccessKeySecret, RegionEndpoint.GetBySystemName(globalSettings.Amazon.Region));
|
||||||
_source = $"\"{globalSettings.SiteName}\" <{globalSettings.Mail.ReplyToEmail}>";
|
_source = $"\"{globalSettings.SiteName}\" <{globalSettings.Mail.ReplyToEmail}>";
|
||||||
_senderTag = $"Server: {globalSettings.ProjectName}";
|
_senderTag = $"Server_{globalSettings.ProjectName}";
|
||||||
|
if(!string.IsNullOrWhiteSpace(_globalSettings.Mail.AmazonConfigSetName))
|
||||||
|
{
|
||||||
|
_configSetName = _globalSettings.Mail.AmazonConfigSetName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@ -56,7 +61,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
var request = new SendEmailRequest
|
var request = new SendEmailRequest
|
||||||
{
|
{
|
||||||
ConfigurationSetName = "Email",
|
ConfigurationSetName = _configSetName,
|
||||||
Source = _source,
|
Source = _source,
|
||||||
Destination = new Destination
|
Destination = new Destination
|
||||||
{
|
{
|
||||||
@ -91,11 +96,9 @@ namespace Bit.Core.Services
|
|||||||
request.Destination.BccAddresses = message.BccEmails.ToList();
|
request.Destination.BccAddresses = message.BccEmails.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(message.MetaData?.ContainsKey("SendGridCategories") ?? false)
|
if(!string.IsNullOrWhiteSpace(message.Category))
|
||||||
{
|
{
|
||||||
var cats = (message.MetaData["SendGridCategories"] as List<string>)
|
request.Tags.Add(new MessageTag { Name = "Category", Value = message.Category });
|
||||||
.Select(c => new MessageTag { Name = "Category", Value = c });
|
|
||||||
request.Tags.AddRange(cats);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -104,7 +107,7 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Failed to send email.");
|
_logger.LogWarning(e, "Failed to send email. Re-retying...");
|
||||||
await SendAsync(request, true);
|
await SendAsync(request, true);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -117,7 +120,6 @@ namespace Bit.Core.Services
|
|||||||
// wait and try again
|
// wait and try again
|
||||||
await Task.Delay(2000);
|
await Task.Delay(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _client.SendEmailAsync(request);
|
await _client.SendEmailAsync(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace Bit.Core.Services
|
|||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "VerifyEmail", model);
|
await AddMessageContentAsync(message, "VerifyEmail", model);
|
||||||
message.MetaData.Add("SendGridBypassListManagement", true);
|
message.MetaData.Add("SendGridBypassListManagement", true);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "VerifyEmail" });
|
message.Category = "VerifyEmail";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ namespace Bit.Core.Services
|
|||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "VerifyDelete", model);
|
await AddMessageContentAsync(message, "VerifyDelete", model);
|
||||||
message.MetaData.Add("SendGridBypassListManagement", true);
|
message.MetaData.Add("SendGridBypassListManagement", true);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "VerifyDelete" });
|
message.Category = "VerifyDelete";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ namespace Bit.Core.Services
|
|||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "ChangeEmailAlreadyExists", model);
|
await AddMessageContentAsync(message, "ChangeEmailAlreadyExists", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "ChangeEmailAlreadyExists" });
|
message.Category = "ChangeEmailAlreadyExists";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ namespace Bit.Core.Services
|
|||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "ChangeEmail", model);
|
await AddMessageContentAsync(message, "ChangeEmail", model);
|
||||||
message.MetaData.Add("SendGridBypassListManagement", true);
|
message.MetaData.Add("SendGridBypassListManagement", true);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "ChangeEmail" });
|
message.Category = "ChangeEmail";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ namespace Bit.Core.Services
|
|||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "TwoFactorEmail", model);
|
await AddMessageContentAsync(message, "TwoFactorEmail", model);
|
||||||
message.MetaData.Add("SendGridBypassListManagement", true);
|
message.MetaData.Add("SendGridBypassListManagement", true);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "TwoFactorEmail" });
|
message.Category = "TwoFactorEmail";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ namespace Bit.Core.Services
|
|||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "MasterPasswordHint", model);
|
await AddMessageContentAsync(message, "MasterPasswordHint", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "MasterPasswordHint" });
|
message.Category = "MasterPasswordHint";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ namespace Bit.Core.Services
|
|||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "NoMasterPasswordHint", model);
|
await AddMessageContentAsync(message, "NoMasterPasswordHint", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "NoMasterPasswordHint" });
|
message.Category = "NoMasterPasswordHint";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ namespace Bit.Core.Services
|
|||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "OrganizationUserAccepted", model);
|
await AddMessageContentAsync(message, "OrganizationUserAccepted", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "OrganizationUserAccepted" });
|
message.Category = "OrganizationUserAccepted";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ namespace Bit.Core.Services
|
|||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "OrganizationUserConfirmed", model);
|
await AddMessageContentAsync(message, "OrganizationUserConfirmed", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "OrganizationUserConfirmed" });
|
message.Category = "OrganizationUserConfirmed";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ namespace Bit.Core.Services
|
|||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "OrganizationUserInvited", model);
|
await AddMessageContentAsync(message, "OrganizationUserInvited", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "OrganizationUserInvited" });
|
message.Category = "OrganizationUserInvited";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ namespace Bit.Core.Services
|
|||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "Welcome", model);
|
await AddMessageContentAsync(message, "Welcome", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "Welcome" });
|
message.Category = "Welcome";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ namespace Bit.Core.Services
|
|||||||
Url = url.ToString()
|
Url = url.ToString()
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "PasswordlessSignIn", model);
|
await AddMessageContentAsync(message, "PasswordlessSignIn", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "PasswordlessSignIn" });
|
message.Category = "PasswordlessSignIn";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ namespace Bit.Core.Services
|
|||||||
MentionInvoices = mentionInvoices
|
MentionInvoices = mentionInvoices
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "InvoiceUpcoming", model);
|
await AddMessageContentAsync(message, "InvoiceUpcoming", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "InvoiceUpcoming" });
|
message.Category = "InvoiceUpcoming";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ namespace Bit.Core.Services
|
|||||||
MentionInvoices = mentionInvoices
|
MentionInvoices = mentionInvoices
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "PaymentFailed", model);
|
await AddMessageContentAsync(message, "PaymentFailed", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "PaymentFailed" });
|
message.Category = "PaymentFailed";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ namespace Bit.Core.Services
|
|||||||
Amount = amount
|
Amount = amount
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "AddedCredit", model);
|
await AddMessageContentAsync(message, "AddedCredit", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "AddedCredit" });
|
message.Category = "AddedCredit";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ namespace Bit.Core.Services
|
|||||||
IpAddress = ip
|
IpAddress = ip
|
||||||
};
|
};
|
||||||
await AddMessageContentAsync(message, "NewDeviceLoggedIn", model);
|
await AddMessageContentAsync(message, "NewDeviceLoggedIn", model);
|
||||||
message.MetaData.Add("SendGridCategories", new List<string> { "NewDeviceLoggedIn" });
|
message.Category = "NewDeviceLoggedIn";
|
||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,9 +58,9 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cats = new List<string> { "Bitwarden Server" };
|
var cats = new List<string> { "Bitwarden Server" };
|
||||||
if(message.MetaData?.ContainsKey("SendGridCategories") ?? false)
|
if(!string.IsNullOrWhiteSpace(message.Category))
|
||||||
{
|
{
|
||||||
cats.AddRange(message.MetaData["SendGridCategories"] as List<string>);
|
cats.Add(message.Category);
|
||||||
}
|
}
|
||||||
sendGridMessage.AddCategories(cats);
|
sendGridMessage.AddCategories(cats);
|
||||||
|
|
||||||
|
@ -87,6 +87,10 @@ namespace Bit.Core.Utilities
|
|||||||
{
|
{
|
||||||
services.AddSingleton<IMailDeliveryService, SendGridMailDeliveryService>();
|
services.AddSingleton<IMailDeliveryService, SendGridMailDeliveryService>();
|
||||||
}
|
}
|
||||||
|
else if(CoreHelpers.SettingHasValue(globalSettings.Amazon?.AccessKeySecret))
|
||||||
|
{
|
||||||
|
services.AddSingleton<IMailDeliveryService, AmazonSesMailDeliveryService>();
|
||||||
|
}
|
||||||
else if(CoreHelpers.SettingHasValue(globalSettings.Mail?.Smtp?.Host))
|
else if(CoreHelpers.SettingHasValue(globalSettings.Mail?.Smtp?.Host))
|
||||||
{
|
{
|
||||||
services.AddSingleton<IMailDeliveryService, MailKitSmtpMailDeliveryService>();
|
services.AddSingleton<IMailDeliveryService, MailKitSmtpMailDeliveryService>();
|
||||||
|
@ -32,6 +32,11 @@
|
|||||||
},
|
},
|
||||||
"sentry": {
|
"sentry": {
|
||||||
"dsn": "SECRET"
|
"dsn": "SECRET"
|
||||||
|
},
|
||||||
|
"amazon": {
|
||||||
|
"accessKeyId": "SECRET",
|
||||||
|
"accessKeySecret": "SECRET",
|
||||||
|
"region": "SECRET"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"mail": {
|
"mail": {
|
||||||
"sendGridApiKey": "SECRET",
|
"sendGridApiKey": "SECRET",
|
||||||
|
"amazonConfigSetName": "Email",
|
||||||
"replyToEmail": "hello@bitwarden.com"
|
"replyToEmail": "hello@bitwarden.com"
|
||||||
},
|
},
|
||||||
"identityServer": {
|
"identityServer": {
|
||||||
@ -58,6 +59,11 @@
|
|||||||
"merchantId": "SECRET",
|
"merchantId": "SECRET",
|
||||||
"publicKey": "SECRET",
|
"publicKey": "SECRET",
|
||||||
"privateKey": "SECRET"
|
"privateKey": "SECRET"
|
||||||
|
},
|
||||||
|
"amazon": {
|
||||||
|
"accessKeyId": "SECRET",
|
||||||
|
"accessKeySecret": "SECRET",
|
||||||
|
"region": "SECRET"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"IpRateLimitOptions": {
|
"IpRateLimitOptions": {
|
||||||
|
@ -32,6 +32,11 @@
|
|||||||
},
|
},
|
||||||
"sentry": {
|
"sentry": {
|
||||||
"dsn": "SECRET"
|
"dsn": "SECRET"
|
||||||
|
},
|
||||||
|
"amazon": {
|
||||||
|
"accessKeyId": "SECRET",
|
||||||
|
"accessKeySecret": "SECRET",
|
||||||
|
"region": "SECRET"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user