Email is now Built-in! (#2635)
This commit is contained in:
parent
2a539da24c
commit
a85644fb6b
55 changed files with 5129 additions and 1047 deletions
|
|
@ -53,6 +53,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MailKit" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
@ -190,6 +191,9 @@
|
|||
|
||||
<ItemGroup>
|
||||
<Folder Include="config\themes" />
|
||||
<Content Include="EmailTemplates\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="I18N\**" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -334,7 +334,9 @@ public class AccountController : BaseApiController
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// Initiates the flow to update a user's email address. The email address is not changed in this API. A confirmation link is sent/dumped which will
|
||||
/// Initiates the flow to update a user's email address.
|
||||
///
|
||||
/// If email is not setup, then the email address is not changed in this API. A confirmation link is sent/dumped which will
|
||||
/// validate the email. It must be confirmed for the email to update.
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
|
|
@ -374,10 +376,22 @@ public class AccountController : BaseApiController
|
|||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generate-token"));
|
||||
}
|
||||
|
||||
user.EmailConfirmed = false;
|
||||
var serverSettings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var shouldEmailUser = serverSettings.IsEmailSetup() || !_emailService.IsValidEmail(user.Email);
|
||||
user.EmailConfirmed = !shouldEmailUser;
|
||||
user.ConfirmationToken = token;
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
if (!shouldEmailUser)
|
||||
{
|
||||
return Ok(new InviteUserResponse
|
||||
{
|
||||
EmailLink = string.Empty,
|
||||
EmailSent = false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Send a confirmation email
|
||||
try
|
||||
{
|
||||
|
|
@ -396,30 +410,27 @@ public class AccountController : BaseApiController
|
|||
}
|
||||
|
||||
|
||||
var accessible = await _accountService.CheckIfAccessible(Request);
|
||||
if (accessible)
|
||||
try
|
||||
{
|
||||
try
|
||||
var invitingUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).First().UserName!;
|
||||
// Email the old address of the update change
|
||||
BackgroundJob.Enqueue(() => _emailService.SendEmailChangeEmail(new ConfirmationEmailDto()
|
||||
{
|
||||
// Email the old address of the update change
|
||||
await _emailService.SendEmailChangeEmail(new ConfirmationEmailDto()
|
||||
{
|
||||
EmailAddress = string.IsNullOrEmpty(user.Email) ? dto.Email : user.Email,
|
||||
InstallId = BuildInfo.Version.ToString(),
|
||||
InvitingUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).First().UserName!,
|
||||
ServerConfirmationLink = emailLink
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow exception */
|
||||
}
|
||||
EmailAddress = string.IsNullOrEmpty(user.Email) ? dto.Email : user.Email,
|
||||
InstallId = BuildInfo.Version.ToString(),
|
||||
InvitingUser = invitingUser,
|
||||
ServerConfirmationLink = emailLink
|
||||
}));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow exception */
|
||||
}
|
||||
|
||||
return Ok(new InviteUserResponse
|
||||
{
|
||||
EmailLink = string.Empty,
|
||||
EmailSent = accessible
|
||||
EmailSent = true
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -579,8 +590,7 @@ public class AccountController : BaseApiController
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// Invites a user to the server. Will generate a setup link for continuing setup. If the server is not accessible, no
|
||||
/// email will be sent.
|
||||
/// Invites a user to the server. Will generate a setup link for continuing setup. If email is not setup, a link will be presented to user to continue setup.
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
|
|
@ -679,15 +689,15 @@ public class AccountController : BaseApiController
|
|||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-invite-user"));
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var emailLink = await _accountService.GenerateEmailLink(Request, user.ConfirmationToken, "confirm-email", dto.Email);
|
||||
_logger.LogCritical("[Invite User]: Email Link for {UserName}: {Link}", user.UserName, emailLink);
|
||||
|
||||
if (!_emailService.IsValidEmail(dto.Email))
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
if (!_emailService.IsValidEmail(dto.Email) || !settings.IsEmailSetup())
|
||||
{
|
||||
_logger.LogInformation("[Invite User] {Email} doesn't appear to be an email, so will not send an email to address", dto.Email.Replace(Environment.NewLine, string.Empty));
|
||||
_logger.LogInformation("[Invite User] {Email} doesn't appear to be an email or email is not setup", dto.Email.Replace(Environment.NewLine, string.Empty));
|
||||
return Ok(new InviteUserResponse
|
||||
{
|
||||
EmailLink = emailLink,
|
||||
|
|
@ -696,22 +706,17 @@ public class AccountController : BaseApiController
|
|||
});
|
||||
}
|
||||
|
||||
var accessible = await _accountService.CheckIfAccessible(Request);
|
||||
if (accessible)
|
||||
BackgroundJob.Enqueue(() => _emailService.SendInviteEmail(new ConfirmationEmailDto()
|
||||
{
|
||||
// Do the email send on a background thread to ensure UI can move forward without having to wait for a timeout when users use fake emails
|
||||
BackgroundJob.Enqueue(() => _emailService.SendConfirmationEmail(new ConfirmationEmailDto()
|
||||
{
|
||||
EmailAddress = dto.Email,
|
||||
InvitingUser = adminUser.UserName,
|
||||
ServerConfirmationLink = emailLink
|
||||
}));
|
||||
}
|
||||
EmailAddress = dto.Email,
|
||||
InvitingUser = adminUser.UserName,
|
||||
ServerConfirmationLink = emailLink
|
||||
}));
|
||||
|
||||
return Ok(new InviteUserResponse
|
||||
{
|
||||
EmailLink = emailLink,
|
||||
EmailSent = accessible
|
||||
EmailSent = true
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -837,7 +842,6 @@ public class AccountController : BaseApiController
|
|||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate,
|
||||
MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
|
||||
|
||||
// Perform Login code
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
|
@ -882,6 +886,10 @@ public class AccountController : BaseApiController
|
|||
[EnableRateLimiting("Authentication")]
|
||||
public async Task<ActionResult<string>> ForgotPassword([FromQuery] string email)
|
||||
{
|
||||
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
if (!settings.IsEmailSetup()) return Ok(await _localizationService.Get("en", "email-not-enabled"));
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(email);
|
||||
if (user == null)
|
||||
{
|
||||
|
|
@ -896,26 +904,28 @@ public class AccountController : BaseApiController
|
|||
if (string.IsNullOrEmpty(user.Email) || !user.EmailConfirmed)
|
||||
return BadRequest(await _localizationService.Translate(user.Id, "confirm-email"));
|
||||
|
||||
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||
var emailLink = await _accountService.GenerateEmailLink(Request, token, "confirm-reset-password", user.Email);
|
||||
_logger.LogCritical("[Forgot Password]: Email Link for {UserName}: {Link}", user.UserName, emailLink);
|
||||
if (!_emailService.IsValidEmail(user.Email))
|
||||
{
|
||||
_logger.LogCritical("[Forgot Password]: User is trying to do a forgot password flow, but their email ({Email}) isn't valid. No email will be send", user.Email);
|
||||
_logger.LogCritical("[Forgot Password]: User is trying to do a forgot password flow, but their email ({Email}) isn't valid. No email will be send. Admin must change it in UI", user.Email);
|
||||
return Ok(await _localizationService.Translate(user.Id, "invalid-email"));
|
||||
}
|
||||
if (await _accountService.CheckIfAccessible(Request))
|
||||
{
|
||||
await _emailService.SendPasswordResetEmail(new PasswordResetEmailDto()
|
||||
{
|
||||
EmailAddress = user.Email,
|
||||
ServerConfirmationLink = emailLink,
|
||||
InstallId = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId)).Value
|
||||
});
|
||||
return Ok(await _localizationService.Translate(user.Id, "email-sent"));
|
||||
}
|
||||
|
||||
return Ok(await _localizationService.Translate(user.Id, "not-accessible-password"));
|
||||
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||
var emailLink = await _accountService.GenerateEmailLink(Request, token, "confirm-reset-password", user.Email);
|
||||
user.ConfirmationToken = token;
|
||||
_unitOfWork.UserRepository.Update(user);
|
||||
await _unitOfWork.CommitAsync();
|
||||
_logger.LogCritical("[Forgot Password]: Email Link for {UserName}: {Link}", user.UserName, emailLink);
|
||||
|
||||
var installId = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId)).Value;
|
||||
BackgroundJob.Enqueue(() => _emailService.SendForgotPasswordEmail(new PasswordResetEmailDto()
|
||||
{
|
||||
EmailAddress = user.Email,
|
||||
ServerConfirmationLink = emailLink,
|
||||
InstallId = installId
|
||||
}));
|
||||
|
||||
return Ok(await _localizationService.Translate(user.Id, "email-sent"));
|
||||
}
|
||||
|
||||
[HttpGet("email-confirmed")]
|
||||
|
|
@ -965,7 +975,7 @@ public class AccountController : BaseApiController
|
|||
/// <returns></returns>
|
||||
[HttpPost("resend-confirmation-email")]
|
||||
[EnableRateLimiting("Authentication")]
|
||||
public async Task<ActionResult<string>> ResendConfirmationSendEmail([FromQuery] int userId)
|
||||
public async Task<ActionResult<InviteUserResponse>> ResendConfirmationSendEmail([FromQuery] int userId)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
if (user == null) return BadRequest(await _localizationService.Get("en", "no-user"));
|
||||
|
|
@ -976,96 +986,47 @@ public class AccountController : BaseApiController
|
|||
if (user.EmailConfirmed) return BadRequest(await _localizationService.Translate(user.Id, "user-already-confirmed"));
|
||||
|
||||
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var emailLink = await _accountService.GenerateEmailLink(Request, token, "confirm-email", user.Email);
|
||||
user.ConfirmationToken = token;
|
||||
_unitOfWork.UserRepository.Update(user);
|
||||
await _unitOfWork.CommitAsync();
|
||||
var emailLink = await _accountService.GenerateEmailLink(Request, token, "confirm-email-update", user.Email);
|
||||
_logger.LogCritical("[Email Migration]: Email Link for {UserName}: {Link}", user.UserName, emailLink);
|
||||
|
||||
if (!_emailService.IsValidEmail(user.Email))
|
||||
{
|
||||
_logger.LogCritical("[Email Migration]: User {UserName} is trying to resend an invite flow, but their email ({Email}) isn't valid. No email will be send", user.UserName, user.Email);
|
||||
return BadRequest(await _localizationService.Translate(user.Id, "invalid-email"));
|
||||
}
|
||||
|
||||
if (await _accountService.CheckIfAccessible(Request))
|
||||
|
||||
var serverSettings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var shouldEmailUser = serverSettings.IsEmailSetup() || !_emailService.IsValidEmail(user.Email);
|
||||
|
||||
if (!shouldEmailUser)
|
||||
{
|
||||
try
|
||||
return Ok(new InviteUserResponse()
|
||||
{
|
||||
await _emailService.SendMigrationEmail(new EmailMigrationDto()
|
||||
{
|
||||
EmailAddress = user.Email!,
|
||||
Username = user.UserName!,
|
||||
ServerConfirmationLink = emailLink,
|
||||
InstallId = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId)).Value
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "There was an issue resending invite email");
|
||||
return BadRequest(await _localizationService.Translate(user.Id, "generic-invite-email"));
|
||||
}
|
||||
return Ok(emailLink);
|
||||
EmailLink = emailLink,
|
||||
EmailSent = false,
|
||||
InvalidEmail = !_emailService.IsValidEmail(user.Email)
|
||||
});
|
||||
}
|
||||
|
||||
return BadRequest(await _localizationService.Translate(user.Id, "not-accessible"));
|
||||
BackgroundJob.Enqueue(() => _emailService.SendInviteEmail(new ConfirmationEmailDto()
|
||||
{
|
||||
EmailAddress = user.Email!,
|
||||
InvitingUser = User.GetUsername(),
|
||||
ServerConfirmationLink = emailLink,
|
||||
InstallId = serverSettings.InstallId
|
||||
}));
|
||||
|
||||
return Ok(new InviteUserResponse()
|
||||
{
|
||||
EmailLink = emailLink,
|
||||
EmailSent = true,
|
||||
InvalidEmail = !_emailService.IsValidEmail(user.Email)
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is similar to invite. Essentially we authenticate the user's password then go through invite email flow
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("migrate-email")]
|
||||
public async Task<ActionResult<string>> MigrateEmail(MigrateUserEmailDto dto)
|
||||
{
|
||||
// If there is an admin account already, return
|
||||
var users = await _unitOfWork.UserRepository.GetAdminUsersAsync();
|
||||
if (users.Any()) return BadRequest(await _localizationService.Get("en", "admin-already-exists"));
|
||||
|
||||
// Check if there is an existing invite
|
||||
var emailValidationErrors = await _accountService.ValidateEmail(dto.Email);
|
||||
if (emailValidationErrors.Any())
|
||||
{
|
||||
var invitedUser = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
||||
if (await _userManager.IsEmailConfirmedAsync(invitedUser!))
|
||||
return BadRequest(await _localizationService.Get("en", "user-already-registered", invitedUser!.UserName));
|
||||
|
||||
_logger.LogInformation("A user is attempting to login, but hasn't accepted email invite");
|
||||
return BadRequest(await _localizationService.Get("en", "user-already-invited"));
|
||||
}
|
||||
|
||||
|
||||
var user = await _userManager.Users
|
||||
.Include(u => u.UserPreferences)
|
||||
.SingleOrDefaultAsync(x => x.NormalizedUserName == dto.Username.ToUpper());
|
||||
if (user == null) return BadRequest(await _localizationService.Get("en", "invalid-username"));
|
||||
|
||||
var validPassword = await _signInManager.UserManager.CheckPasswordAsync(user, dto.Password);
|
||||
if (!validPassword) return BadRequest(await _localizationService.Get("en", "bad-credentials"));
|
||||
|
||||
try
|
||||
{
|
||||
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
|
||||
user.Email = dto.Email;
|
||||
if (!await ConfirmEmailToken(token, user)) return BadRequest(await _localizationService.Get("en", "critical-email-migration"));
|
||||
_unitOfWork.UserRepository.Update(user);
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "There was an issue during email migration. Contact support");
|
||||
_unitOfWork.UserRepository.Delete(user);
|
||||
await _unitOfWork.CommitAsync();
|
||||
}
|
||||
|
||||
return BadRequest(await _localizationService.Get("en", "critical-email-migration"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task<bool> ConfirmEmailToken(string token, AppUser user)
|
||||
{
|
||||
var result = await _userManager.ConfirmEmailAsync(user, token);
|
||||
|
|
|
|||
|
|
@ -92,18 +92,28 @@ public class DeviceController : BaseApiController
|
|||
return Ok(await _unitOfWork.DeviceRepository.GetDevicesForUserAsync(User.GetUserId()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a collection of chapters to the user's device
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("send-to")]
|
||||
public async Task<ActionResult> SendToDevice(SendToDeviceDto dto)
|
||||
{
|
||||
if (dto.ChapterIds.Any(i => i < 0)) return BadRequest(await _localizationService.Translate(User.GetUserId(), "greater-0", "ChapterIds"));
|
||||
if (dto.DeviceId < 0) return BadRequest(await _localizationService.Translate(User.GetUserId(), "greater-0", "DeviceId"));
|
||||
|
||||
if (await _emailService.IsDefaultEmailService())
|
||||
var isEmailSetup = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).IsEmailSetup();
|
||||
if (!isEmailSetup)
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "send-to-kavita-email"));
|
||||
|
||||
// // Validate that the device belongs to the user
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Devices);
|
||||
if (user == null || user.Devices.All(d => d.Id != dto.DeviceId)) return BadRequest(await _localizationService.Translate(User.GetUserId(), "send-to-unallowed"));
|
||||
|
||||
var userId = User.GetUserId();
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.NotificationProgress,
|
||||
MessageFactory.SendingToDeviceEvent(await _localizationService.Translate(User.GetUserId(), "send-to-device-status"),
|
||||
MessageFactory.SendingToDeviceEvent(await _localizationService.Translate(userId, "send-to-device-status"),
|
||||
"started"), userId);
|
||||
try
|
||||
{
|
||||
|
|
@ -112,16 +122,16 @@ public class DeviceController : BaseApiController
|
|||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), ex.Message));
|
||||
return BadRequest(await _localizationService.Translate(userId, ex.Message));
|
||||
}
|
||||
finally
|
||||
{
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.SendingToDevice,
|
||||
MessageFactory.SendingToDeviceEvent(await _localizationService.Translate(User.GetUserId(), "send-to-device-status"),
|
||||
MessageFactory.SendingToDeviceEvent(await _localizationService.Translate(userId, "send-to-device-status"),
|
||||
"ended"), userId);
|
||||
}
|
||||
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-send-to"));
|
||||
return BadRequest(await _localizationService.Translate(userId, "generic-send-to"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,19 +14,9 @@ namespace API.Controllers;
|
|||
|
||||
#nullable enable
|
||||
|
||||
public class PluginController : BaseApiController
|
||||
public class PluginController(IUnitOfWork unitOfWork, ITokenService tokenService, ILogger<PluginController> logger)
|
||||
: BaseApiController
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly ITokenService _tokenService;
|
||||
private readonly ILogger<PluginController> _logger;
|
||||
|
||||
public PluginController(IUnitOfWork unitOfWork, ITokenService tokenService, ILogger<PluginController> logger)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_tokenService = tokenService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticate with the Server given an apiKey. This will log you in by returning the user object and the JWT token.
|
||||
/// </summary>
|
||||
|
|
@ -42,11 +32,11 @@ public class PluginController : BaseApiController
|
|||
// NOTE: In order to log information about plugins, we need some Plugin Description information for each request
|
||||
// Should log into access table so we can tell the user
|
||||
var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
var userAgent = HttpContext.Request.Headers["User-Agent"];
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
var userAgent = HttpContext.Request.Headers.UserAgent;
|
||||
var userId = await unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
if (userId <= 0)
|
||||
{
|
||||
_logger.LogInformation("A Plugin ({PluginName}) tried to authenticate with an apiKey that doesn't match. Information {@Information}", pluginName.Replace(Environment.NewLine, string.Empty), new
|
||||
logger.LogInformation("A Plugin ({PluginName}) tried to authenticate with an apiKey that doesn't match. Information {@Information}", pluginName.Replace(Environment.NewLine, string.Empty), new
|
||||
{
|
||||
IpAddress = ipAddress,
|
||||
UserAgent = userAgent,
|
||||
|
|
@ -54,15 +44,15 @@ public class PluginController : BaseApiController
|
|||
});
|
||||
throw new KavitaUnauthenticatedUserException();
|
||||
}
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
_logger.LogInformation("Plugin {PluginName} has authenticated with {UserName} ({UserId})'s API Key", pluginName.Replace(Environment.NewLine, string.Empty), user!.UserName, userId);
|
||||
var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
logger.LogInformation("Plugin {PluginName} has authenticated with {UserName} ({UserId})'s API Key", pluginName.Replace(Environment.NewLine, string.Empty), user!.UserName, userId);
|
||||
return new UserDto
|
||||
{
|
||||
Username = user.UserName!,
|
||||
Token = await _tokenService.CreateToken(user),
|
||||
RefreshToken = await _tokenService.CreateRefreshToken(user),
|
||||
Token = await tokenService.CreateToken(user),
|
||||
RefreshToken = await tokenService.CreateRefreshToken(user),
|
||||
ApiKey = user.ApiKey,
|
||||
KavitaVersion = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion)).Value
|
||||
KavitaVersion = (await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion)).Value
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -76,8 +66,8 @@ public class PluginController : BaseApiController
|
|||
[HttpGet("version")]
|
||||
public async Task<ActionResult<string>> GetVersion([Required] string apiKey)
|
||||
{
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
var userId = await unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
if (userId <= 0) throw new KavitaUnauthenticatedUserException();
|
||||
return Ok((await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion)).Value);
|
||||
return Ok((await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion)).Value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,22 +275,6 @@ public class ServerController : BaseApiController
|
|||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the KavitaEmail version for non-default instances
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Authorize("RequireAdminRole")]
|
||||
[HttpGet("email-version")]
|
||||
public async Task<ActionResult<string?>> GetEmailVersion()
|
||||
{
|
||||
var emailServiceUrl = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl))
|
||||
.Value;
|
||||
|
||||
if (emailServiceUrl.Equals(EmailService.DefaultApiUrl)) return Ok(null);
|
||||
|
||||
return Ok(await _emailService.GetVersion(emailServiceUrl));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for updates and pushes an event to the UI
|
||||
/// </summary>
|
||||
|
|
@ -301,5 +285,4 @@ public class ServerController : BaseApiController
|
|||
await _taskScheduler.CheckForUpdate();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||
using API.Data;
|
||||
using API.DTOs.Email;
|
||||
using API.DTOs.Settings;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Helpers.Converters;
|
||||
|
|
@ -119,28 +120,7 @@ public class SettingsController : BaseApiController
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the email service url
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpPost("reset-email-url")]
|
||||
public async Task<ActionResult<ServerSettingDto>> ResetEmailServiceUrlSettings()
|
||||
{
|
||||
_logger.LogInformation("{UserName} is resetting Email Service Url Setting", User.GetUsername());
|
||||
var emailSetting = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl);
|
||||
emailSetting.Value = EmailService.DefaultApiUrl;
|
||||
_unitOfWork.SettingsRepository.Update(emailSetting);
|
||||
|
||||
if (!await _unitOfWork.CommitAsync())
|
||||
{
|
||||
await _unitOfWork.RollbackAsync();
|
||||
}
|
||||
|
||||
return Ok(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a test email from the Email Service. Will not send if email service is the Default Provider
|
||||
/// Sends a test email from the Email Service.
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
|
|
@ -149,8 +129,19 @@ public class SettingsController : BaseApiController
|
|||
public async Task<ActionResult<EmailTestResultDto>> TestEmailServiceUrl(TestEmailDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId());
|
||||
var emailService = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl)).Value;
|
||||
return Ok(await _emailService.TestConnectivity(dto.Url, user!.Email, !emailService.Equals(EmailService.DefaultApiUrl)));
|
||||
return Ok(await _emailService.SendTestEmail(user!.Email));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the minimum information setup for Email to work
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
[HttpGet("is-email-setup")]
|
||||
public async Task<ActionResult<bool>> IsEmailSetup()
|
||||
{
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
return Ok(settings.IsEmailSetup());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -233,6 +224,10 @@ public class SettingsController : BaseApiController
|
|||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
UpdateEmailSettings(setting, updateSettingsDto);
|
||||
|
||||
|
||||
|
||||
if (setting.Key == ServerSettingKey.IpAddresses && updateSettingsDto.IpAddresses != setting.Value)
|
||||
{
|
||||
if (OsInfo.IsDocker) continue;
|
||||
|
|
@ -289,17 +284,6 @@ public class SettingsController : BaseApiController
|
|||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailServiceUrl && updateSettingsDto.EmailServiceUrl + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = string.IsNullOrEmpty(updateSettingsDto.EmailServiceUrl) ? EmailService.DefaultApiUrl : updateSettingsDto.EmailServiceUrl;
|
||||
setting.Value = UrlHelper.RemoveEndingSlash(setting.Value);
|
||||
FlurlHttp.ConfigureClient(setting.Value, cli =>
|
||||
cli.Settings.HttpClientFactory = new UntrustedCertClientFactory());
|
||||
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
|
||||
if (setting.Key == ServerSettingKey.BookmarkDirectory && bookmarkDirectory != setting.Value)
|
||||
{
|
||||
// Validate new directory can be used
|
||||
|
|
@ -392,6 +376,63 @@ public class SettingsController : BaseApiController
|
|||
return Ok(updateSettingsDto);
|
||||
}
|
||||
|
||||
private void UpdateEmailSettings(ServerSetting setting, ServerSettingDto updateSettingsDto)
|
||||
{
|
||||
if (setting.Key == ServerSettingKey.EmailHost && updateSettingsDto.SmtpConfig.Host + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.Host + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailPort && updateSettingsDto.SmtpConfig.Port + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.Port + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailAuthPassword && updateSettingsDto.SmtpConfig.Password + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.Password + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailAuthUserName && updateSettingsDto.SmtpConfig.UserName + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.UserName + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailSenderAddress && updateSettingsDto.SmtpConfig.SenderAddress + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.SenderAddress + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailSenderDisplayName && updateSettingsDto.SmtpConfig.SenderDisplayName + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.SenderDisplayName + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailSizeLimit && updateSettingsDto.SmtpConfig.SizeLimit + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.SizeLimit + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailEnableSsl && updateSettingsDto.SmtpConfig.EnableSsl + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.EnableSsl + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailCustomizedTemplates && updateSettingsDto.SmtpConfig.CustomizedTemplates + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.SmtpConfig.CustomizedTemplates + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpGet("task-frequencies")]
|
||||
public ActionResult<IEnumerable<string>> GetTaskFrequencies()
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ public class EmailTestResultDto
|
|||
{
|
||||
public bool Successful { get; set; }
|
||||
public string ErrorMessage { get; set; } = default!;
|
||||
public string EmailAddress { get; set; } = default!;
|
||||
}
|
||||
|
|
|
|||
20
API/DTOs/Settings/SMTPConfigDto.cs
Normal file
20
API/DTOs/Settings/SMTPConfigDto.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
namespace API.DTOs.Settings;
|
||||
|
||||
public class SmtpConfigDto
|
||||
{
|
||||
public string SenderAddress { get; set; } = string.Empty;
|
||||
public string SenderDisplayName { get; set; } = string.Empty;
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
public string Host { get; set; } = string.Empty;
|
||||
public int Port { get; set; } = 0;
|
||||
public bool EnableSsl { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Limit in bytes for allowing files to be added as attachments. Defaults to 25MB
|
||||
/// </summary>
|
||||
public int SizeLimit { get; set; } = 26_214_400;
|
||||
/// <summary>
|
||||
/// Should Kavita use config/templates for Email templates or the default ones
|
||||
/// </summary>
|
||||
public bool CustomizedTemplates { get; set; } = false;
|
||||
}
|
||||
|
|
@ -38,11 +38,6 @@ public class ServerSettingDto
|
|||
/// </summary>
|
||||
/// <remarks>If null or empty string, will default back to default install setting aka <see cref="DirectoryService.BookmarkDirectory"/></remarks>
|
||||
public string BookmarksDirectory { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Email service to use for the invite user flow, forgot password, etc.
|
||||
/// </summary>
|
||||
/// <remarks>If null or empty string, will default back to default install setting aka <see cref="EmailService.DefaultApiUrl"/></remarks>
|
||||
public string EmailServiceUrl { get; set; } = default!;
|
||||
public string InstallVersion { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Represents a unique Id to this Kavita installation. Only used in Stats to identify unique installs.
|
||||
|
|
@ -88,4 +83,20 @@ public class ServerSettingDto
|
|||
/// How large the cover images should be
|
||||
/// </summary>
|
||||
public CoverImageSize CoverImageSize { get; set; }
|
||||
/// <summary>
|
||||
/// SMTP Configuration
|
||||
/// </summary>
|
||||
public SmtpConfigDto SmtpConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Are at least some basics filled in
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsEmailSetup()
|
||||
{
|
||||
//return false;
|
||||
return !string.IsNullOrEmpty(SmtpConfig.Host)
|
||||
&& !string.IsNullOrEmpty(SmtpConfig.UserName)
|
||||
&& !string.IsNullOrEmpty(HostName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
59
API/Data/ManualMigrations/MigrateEmailTemplates.cs
Normal file
59
API/Data/ManualMigrations/MigrateEmailTemplates.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Services;
|
||||
using Flurl.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace API.Data.ManualMigrations;
|
||||
|
||||
public static class MigrateEmailTemplates
|
||||
{
|
||||
private const string EmailChange = "https://raw.githubusercontent.com/Kareadita/KavitaEmail/main/KavitaEmail/config/templates/EmailChange.html";
|
||||
private const string EmailConfirm = "https://raw.githubusercontent.com/Kareadita/KavitaEmail/main/KavitaEmail/config/templates/EmailConfirm.html";
|
||||
private const string EmailPasswordReset = "https://raw.githubusercontent.com/Kareadita/KavitaEmail/main/KavitaEmail/config/templates/EmailPasswordReset.html";
|
||||
private const string SendToDevice = "https://raw.githubusercontent.com/Kareadita/KavitaEmail/main/KavitaEmail/config/templates/SendToDevice.html";
|
||||
private const string EmailTest = "https://raw.githubusercontent.com/Kareadita/KavitaEmail/main/KavitaEmail/config/templates/EmailTest.html";
|
||||
|
||||
public static async Task Migrate(IDirectoryService directoryService, ILogger<Program> logger)
|
||||
{
|
||||
var files = directoryService.GetFiles(directoryService.CustomizedTemplateDirectory);
|
||||
if (files.Any())
|
||||
{
|
||||
logger.LogCritical("Running MigrateEmailTemplates migration - Completed. This is not an error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write files to directory
|
||||
await DownloadAndWriteToFile(EmailChange, Path.Join(directoryService.CustomizedTemplateDirectory, "EmailChange.html"), logger);
|
||||
await DownloadAndWriteToFile(EmailConfirm, Path.Join(directoryService.CustomizedTemplateDirectory, "EmailConfirm.html"), logger);
|
||||
await DownloadAndWriteToFile(EmailPasswordReset, Path.Join(directoryService.CustomizedTemplateDirectory, "EmailPasswordReset.html"), logger);
|
||||
await DownloadAndWriteToFile(SendToDevice, Path.Join(directoryService.CustomizedTemplateDirectory, "SendToDevice.html"), logger);
|
||||
await DownloadAndWriteToFile(EmailTest, Path.Join(directoryService.CustomizedTemplateDirectory, "EmailTest.html"), logger);
|
||||
|
||||
|
||||
|
||||
logger.LogCritical("Running MigrateEmailTemplates migration - Please be patient, this may take some time. This is not an error");
|
||||
}
|
||||
|
||||
private static async Task DownloadAndWriteToFile(string url, string filePath, ILogger<Program> logger)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Download the raw text using Flurl
|
||||
var content = await url.GetStringAsync();
|
||||
|
||||
// Write the content to a file
|
||||
await File.WriteAllTextAsync(filePath, content);
|
||||
|
||||
logger.LogInformation("{File} downloaded and written successfully", filePath);
|
||||
}
|
||||
catch (FlurlHttpException ex)
|
||||
{
|
||||
logger.LogError(ex, "Unable to download {Url} to {FilePath}. Please perform yourself!", url, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -223,12 +223,10 @@ public static class Seed
|
|||
}, // Not used from DB, but DB is sync with appSettings.json
|
||||
new() {Key = ServerSettingKey.AllowStatCollection, Value = "true"},
|
||||
new() {Key = ServerSettingKey.EnableOpds, Value = "true"},
|
||||
new() {Key = ServerSettingKey.EnableAuthentication, Value = "true"},
|
||||
new() {Key = ServerSettingKey.BaseUrl, Value = "/"},
|
||||
new() {Key = ServerSettingKey.InstallId, Value = HashUtil.AnonymousToken()},
|
||||
new() {Key = ServerSettingKey.InstallVersion, Value = BuildInfo.Version.ToString()},
|
||||
new() {Key = ServerSettingKey.BookmarkDirectory, Value = directoryService.BookmarkDirectory},
|
||||
new() {Key = ServerSettingKey.EmailServiceUrl, Value = EmailService.DefaultApiUrl},
|
||||
new() {Key = ServerSettingKey.TotalBackups, Value = "30"},
|
||||
new() {Key = ServerSettingKey.TotalLogs, Value = "30"},
|
||||
new() {Key = ServerSettingKey.EnableFolderWatching, Value = "false"},
|
||||
|
|
@ -241,6 +239,16 @@ public static class Seed
|
|||
new() {
|
||||
Key = ServerSettingKey.CacheSize, Value = Configuration.DefaultCacheMemory + string.Empty
|
||||
}, // Not used from DB, but DB is sync with appSettings.json
|
||||
|
||||
new() {Key = ServerSettingKey.EmailHost, Value = string.Empty},
|
||||
new() {Key = ServerSettingKey.EmailPort, Value = string.Empty},
|
||||
new() {Key = ServerSettingKey.EmailAuthPassword, Value = string.Empty},
|
||||
new() {Key = ServerSettingKey.EmailAuthUserName, Value = string.Empty},
|
||||
new() {Key = ServerSettingKey.EmailSenderAddress, Value = string.Empty},
|
||||
new() {Key = ServerSettingKey.EmailSenderDisplayName, Value = string.Empty},
|
||||
new() {Key = ServerSettingKey.EmailEnableSsl, Value = "true"},
|
||||
new() {Key = ServerSettingKey.EmailSizeLimit, Value = 26_214_400 + string.Empty},
|
||||
new() {Key = ServerSettingKey.EmailCustomizedTemplates, Value = "false"},
|
||||
}.ToArray());
|
||||
|
||||
foreach (var defaultSetting in DefaultSettings)
|
||||
|
|
|
|||
348
API/EmailTemplates/EmailChange.html
Normal file
348
API/EmailTemplates/EmailChange.html
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Kavita - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> Your account's email has been updated on {{InvitingUser}}'s Kavita instance. Click the button to validate your email.</div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">Email Change Update</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Your account's email has been updated on {{InvitingUser}}'s Kavita instance.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Please click the following link to validate your email change. The email is not changed until you complete validation.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||
<!-- Button : BEGIN -->
|
||||
<center>
|
||||
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow" style="text-align: center;">
|
||||
<tr>
|
||||
<td style="border-radius: 50px; background: #153643; text-align: center;" class="button-td">
|
||||
<a href="{{Link}}" style="background: #153643; border: 15px solid #153643; font-family: 'Montserrat', sans-serif; font-size: 14px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 50px; font-weight: bold;" class="button-a"> <span style="color:#ffffff;" class="button-link"> CONFIRM EMAIL </span> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<!-- Button : END -->
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If the button above does not work, please find the link here: <a style="color:inherit;margin: 0;width: 100%;word-break: break-all;" href="{{Link}}">{{Link}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
348
API/EmailTemplates/EmailConfirm.html
Normal file
348
API/EmailTemplates/EmailConfirm.html
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Kavita - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> You have been invited to {{InvitingUser}}'s Kavita instance. Click the button to accept the invite. </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">You've Been Invited</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">You have been invited to {{InvitingUser}}'s Kavita instance.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Please click the following link to setup an account for yourself and start reading.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||
<!-- Button : BEGIN -->
|
||||
<center>
|
||||
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow" style="text-align: center;">
|
||||
<tr>
|
||||
<td style="border-radius: 50px; background: #153643; text-align: center;" class="button-td">
|
||||
<a href="{{Link}}" style="background: #153643; border: 15px solid #153643; font-family: 'Montserrat', sans-serif; font-size: 14px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 50px; font-weight: bold;" class="button-a"> <span style="color:#ffffff;" class="button-link"> ACCEPT INVITE </span> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<!-- Button : END -->
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If the button above does not work, please find the link here: <a style="color:inherit;margin: 0;width: 100%;word-break: break-all;" href="{{Link}}">{{Link}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
348
API/EmailTemplates/EmailPasswordReset.html
Normal file
348
API/EmailTemplates/EmailPasswordReset.html
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Kavita - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap);
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> Email confirmation is required for continued access. Click the button to confirm your email. </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">Forgot your password?</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">That's okay, it happens! Click on the button below to reset your password.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||
<!-- Button : BEGIN -->
|
||||
<center>
|
||||
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow" style="text-align: center;">
|
||||
<tr>
|
||||
<td style="border-radius: 50px; background: #153643; text-align: center;" class="button-td">
|
||||
<a href="{{Link}}" style="background: #153643; border: 15px solid #153643; font-family: 'Montserrat', sans-serif; font-size: 14px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 50px; font-weight: bold;" class="button-a"> <span style="color:#ffffff;" class="button-link"> RESET YOUR PASSWORD </span> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<!-- Button : END -->
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 0px 20px 0px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If you did not perform this action, ignore this email.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If the button above does not work, please find the link here: <a style="color:inherit;margin: 0;width: 100%;word-break: break-all;" href="{{Link}}">{{Link}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
325
API/EmailTemplates/EmailTest.html
Normal file
325
API/EmailTemplates/EmailTest.html
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Event - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;">
|
||||
This is a Test Email
|
||||
</div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">This is a Test Email</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">If you've received this email, your KavitaEmail is setup</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
323
API/EmailTemplates/SendToDevice.html
Normal file
323
API/EmailTemplates/SendToDevice.html
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Event - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> You've been sent a file from Kavita! </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">You sent a file from Kavita</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Please find attached the file(s) you've sent.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -52,6 +52,7 @@ public enum ServerSettingKey
|
|||
/// Is Authentication needed for non-admin accounts
|
||||
/// </summary>
|
||||
/// <remarks>Deprecated. This is no longer used v0.5.1+. Assume Authentication is always in effect</remarks>
|
||||
[Obsolete("Not supported as of v0.5.1")]
|
||||
[Description("EnableAuthentication")]
|
||||
EnableAuthentication = 8,
|
||||
/// <summary>
|
||||
|
|
@ -79,6 +80,7 @@ public enum ServerSettingKey
|
|||
/// If SMTP is enabled on the server
|
||||
/// </summary>
|
||||
[Description("CustomEmailService")]
|
||||
[Obsolete("Use Email settings instead")]
|
||||
EmailServiceUrl = 13,
|
||||
/// <summary>
|
||||
/// If Kavita should save bookmarks as WebP images
|
||||
|
|
@ -147,6 +149,38 @@ public enum ServerSettingKey
|
|||
/// The size of the cover image thumbnail. Defaults to <see cref="CoverImageSize"/>.Default
|
||||
/// </summary>
|
||||
[Description("CoverImageSize")]
|
||||
CoverImageSize = 27
|
||||
CoverImageSize = 27,
|
||||
#region EmailSettings
|
||||
/// <summary>
|
||||
/// The address of the emailer host
|
||||
/// </summary>
|
||||
[Description("EmailSenderAddress")]
|
||||
EmailSenderAddress = 28,
|
||||
/// <summary>
|
||||
/// What the email name should be
|
||||
/// </summary>
|
||||
[Description("EmailSenderDisplayName")]
|
||||
EmailSenderDisplayName = 29,
|
||||
[Description("EmailAuthUserName")]
|
||||
EmailAuthUserName = 30,
|
||||
[Description("EmailAuthPassword")]
|
||||
EmailAuthPassword = 31,
|
||||
[Description("EmailHost")]
|
||||
EmailHost = 32,
|
||||
[Description("EmailPort")]
|
||||
EmailPort = 33,
|
||||
[Description("EmailEnableSsl")]
|
||||
EmailEnableSsl = 34,
|
||||
/// <summary>
|
||||
/// Number of bytes that the sender allows to be sent through
|
||||
/// </summary>
|
||||
[Description("EmailSizeLimit")]
|
||||
EmailSizeLimit = 35,
|
||||
/// <summary>
|
||||
/// Should Kavita use config/templates for Email templates or the default ones
|
||||
/// </summary>
|
||||
[Description("EmailCustomizedTemplates")]
|
||||
EmailCustomizedTemplates = 36,
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,9 +47,6 @@ public class ServerSettingConverter : ITypeConverter<IEnumerable<ServerSetting>,
|
|||
case ServerSettingKey.BookmarkDirectory:
|
||||
destination.BookmarksDirectory = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.EmailServiceUrl:
|
||||
destination.EmailServiceUrl = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.InstallVersion:
|
||||
destination.InstallVersion = row.Value;
|
||||
break;
|
||||
|
|
@ -83,6 +80,45 @@ public class ServerSettingConverter : ITypeConverter<IEnumerable<ServerSetting>,
|
|||
case ServerSettingKey.CoverImageSize:
|
||||
destination.CoverImageSize = Enum.Parse<CoverImageSize>(row.Value);
|
||||
break;
|
||||
case ServerSettingKey.BackupDirectory:
|
||||
destination.BookmarksDirectory = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.EmailHost:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.Host = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.EmailPort:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.Port = string.IsNullOrEmpty(row.Value) ? 0 : int.Parse(row.Value);
|
||||
break;
|
||||
case ServerSettingKey.EmailAuthPassword:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.Password = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.EmailAuthUserName:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.UserName = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.EmailSenderAddress:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.SenderAddress = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.EmailSenderDisplayName:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.SenderDisplayName = row.Value;
|
||||
break;
|
||||
case ServerSettingKey.EmailEnableSsl:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.EnableSsl = bool.Parse(row.Value);
|
||||
break;
|
||||
case ServerSettingKey.EmailSizeLimit:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.SizeLimit = int.Parse(row.Value);
|
||||
break;
|
||||
case ServerSettingKey.EmailCustomizedTemplates:
|
||||
destination.SmtpConfig ??= new SmtpConfigDto();
|
||||
destination.SmtpConfig.CustomizedTemplates = bool.Parse(row.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
"admin-already-exists": "Admin already exists",
|
||||
"invalid-username": "Invalid username",
|
||||
"critical-email-migration": "There was an issue during email migration. Contact support",
|
||||
"email-not-enabled": "Email is not enabled on this server. You cannot perform this action.",
|
||||
|
||||
"chapter-doesnt-exist": "Chapter does not exist",
|
||||
"file-missing": "File was not found in book",
|
||||
|
|
@ -53,7 +54,9 @@
|
|||
"generic-device-update": "There was an error when updating the device",
|
||||
"generic-device-delete": "There was an error when deleting the device",
|
||||
"greater-0": "{0} must be greater than 0",
|
||||
"send-to-kavita-email": "Send to device cannot be used with Kavita's email service. Please configure your own.",
|
||||
"send-to-kavita-email": "Send to device cannot be used without Email setup",
|
||||
"send-to-unallowed":"You cannot send to a device that isn't yours",
|
||||
"send-to-size-limit": "The file(s) you are trying to send are too large for your emailer",
|
||||
"send-to-device-status": "Transferring files to your device",
|
||||
"generic-send-to": "There was an error sending the file(s) to the device",
|
||||
"series-doesnt-exist": "Series does not exist",
|
||||
|
|
|
|||
|
|
@ -107,6 +107,10 @@ public class DeviceService : IDeviceService
|
|||
|
||||
public async Task<bool> SendTo(IReadOnlyList<int> chapterIds, int deviceId)
|
||||
{
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
if (!settings.IsEmailSetup())
|
||||
throw new KavitaException("send-to-kavita-email");
|
||||
|
||||
var device = await _unitOfWork.DeviceRepository.GetDeviceById(deviceId);
|
||||
if (device == null) throw new KavitaException("device-doesnt-exist");
|
||||
|
||||
|
|
@ -114,6 +118,10 @@ public class DeviceService : IDeviceService
|
|||
if (files.Any(f => f.Format is not (MangaFormat.Epub or MangaFormat.Pdf)) && device.Platform == DevicePlatform.Kindle)
|
||||
throw new KavitaException("send-to-permission");
|
||||
|
||||
// If the size of the files is too big
|
||||
if (files.Sum(f => f.Bytes) >= settings.SmtpConfig.SizeLimit)
|
||||
throw new KavitaException("send-to-size-limit");
|
||||
|
||||
|
||||
device.UpdateLastUsed();
|
||||
_unitOfWork.DeviceRepository.Update(device);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public interface IDirectoryService
|
|||
string SiteThemeDirectory { get; }
|
||||
string FaviconDirectory { get; }
|
||||
string LocalizationDirectory { get; }
|
||||
string CustomizedTemplateDirectory { get; }
|
||||
string TemplateDirectory { get; }
|
||||
/// <summary>
|
||||
/// Original BookmarkDirectory. Only used for resetting directory. Use <see cref="ServerSettingKey.BackupDirectory"/> for actual path.
|
||||
/// </summary>
|
||||
|
|
@ -81,6 +83,8 @@ public class DirectoryService : IDirectoryService
|
|||
public string SiteThemeDirectory { get; }
|
||||
public string FaviconDirectory { get; }
|
||||
public string LocalizationDirectory { get; }
|
||||
public string CustomizedTemplateDirectory { get; }
|
||||
public string TemplateDirectory { get; }
|
||||
private readonly ILogger<DirectoryService> _logger;
|
||||
private const RegexOptions MatchOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase;
|
||||
|
||||
|
|
@ -114,6 +118,10 @@ public class DirectoryService : IDirectoryService
|
|||
FaviconDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "favicons");
|
||||
ExistOrCreate(FaviconDirectory);
|
||||
LocalizationDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "I18N");
|
||||
CustomizedTemplateDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "templates");
|
||||
ExistOrCreate(CustomizedTemplateDirectory);
|
||||
TemplateDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "EmailTemplates");
|
||||
ExistOrCreate(TemplateDirectory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,34 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.DTOs.Email;
|
||||
using API.Entities.Enums;
|
||||
using Flurl;
|
||||
using Flurl.Http;
|
||||
using Kavita.Common;
|
||||
using Kavita.Common.EnvironmentInfo;
|
||||
using Kavita.Common.Helpers;
|
||||
using MailKit.Security;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MimeKit;
|
||||
|
||||
namespace API.Services;
|
||||
#nullable enable
|
||||
|
||||
internal class EmailOptionsDto
|
||||
{
|
||||
public IList<string> ToEmails { get; set; }
|
||||
public string Subject { get; set; }
|
||||
public string Body { get; set; }
|
||||
public IList<KeyValuePair<string, string>> PlaceHolders { get; set; }
|
||||
/// <summary>
|
||||
/// Filenames to attach
|
||||
/// </summary>
|
||||
public IList<string>? Attachments { get; set; }
|
||||
}
|
||||
|
||||
public interface IEmailService
|
||||
{
|
||||
Task SendConfirmationEmail(ConfirmationEmailDto data);
|
||||
Task SendInviteEmail(ConfirmationEmailDto data);
|
||||
Task<bool> CheckIfAccessible(string host);
|
||||
Task<bool> SendMigrationEmail(EmailMigrationDto data);
|
||||
Task<bool> SendPasswordResetEmail(PasswordResetEmailDto data);
|
||||
Task<bool> SendForgotPasswordEmail(PasswordResetEmailDto dto);
|
||||
Task<bool> SendFilesToEmail(SendToDto data);
|
||||
Task<EmailTestResultDto> TestConnectivity(string emailUrl, string adminEmail, bool sendEmail);
|
||||
Task<EmailTestResultDto> SendTestEmail(string adminEmail);
|
||||
Task<bool> IsDefaultEmailService();
|
||||
Task SendEmailChangeEmail(ConfirmationEmailDto data);
|
||||
Task<string?> GetVersion(string emailUrl);
|
||||
bool IsValidEmail(string email);
|
||||
}
|
||||
|
||||
|
|
@ -37,41 +48,62 @@ public class EmailService : IEmailService
|
|||
private readonly ILogger<EmailService> _logger;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IDownloadService _downloadService;
|
||||
private readonly IDirectoryService _directoryService;
|
||||
|
||||
private const string TemplatePath = @"{0}.html";
|
||||
/// <summary>
|
||||
/// This is used to initially set or reset the ServerSettingKey. Do not access from the code, access via UnitOfWork
|
||||
/// </summary>
|
||||
public const string DefaultApiUrl = "https://email.kavitareader.com";
|
||||
|
||||
public EmailService(ILogger<EmailService> logger, IUnitOfWork unitOfWork, IDownloadService downloadService)
|
||||
|
||||
public EmailService(ILogger<EmailService> logger, IUnitOfWork unitOfWork, IDownloadService downloadService, IDirectoryService directoryService)
|
||||
{
|
||||
_logger = logger;
|
||||
_unitOfWork = unitOfWork;
|
||||
_downloadService = downloadService;
|
||||
|
||||
|
||||
FlurlHttp.ConfigureClient(DefaultApiUrl, cli =>
|
||||
cli.Settings.HttpClientFactory = new UntrustedCertClientFactory());
|
||||
_directoryService = directoryService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if this instance is accessible outside the network
|
||||
/// Test if the email settings are working. Rejects if user email isn't valid or not all data is setup in server settings.
|
||||
/// </summary>
|
||||
/// <remarks>This will do some basic filtering to auto return false if the emailUrl is a LAN ip</remarks>
|
||||
/// <param name="emailUrl"></param>
|
||||
/// <param name="sendEmail">Should an email be sent if connectivity is successful</param>
|
||||
/// <returns></returns>
|
||||
public async Task<EmailTestResultDto> TestConnectivity(string emailUrl, string adminEmail, bool sendEmail)
|
||||
public async Task<EmailTestResultDto> SendTestEmail(string adminEmail)
|
||||
{
|
||||
var result = new EmailTestResultDto();
|
||||
var result = new EmailTestResultDto
|
||||
{
|
||||
EmailAddress = adminEmail
|
||||
};
|
||||
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
if (!IsValidEmail(adminEmail) || !settings.IsEmailSetup())
|
||||
{
|
||||
result.ErrorMessage = "You need to fill in more information in settings and ensure your account has a valid email to send a test email";
|
||||
result.Successful = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Come back and update the template. We can't do it with the v0.8.0 release
|
||||
var placeholders = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new ("{{Host}}", settings.HostName),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
if (IsLocalIpAddress(emailUrl))
|
||||
var emailOptions = new EmailOptionsDto()
|
||||
{
|
||||
result.Successful = false;
|
||||
result.ErrorMessage = "This is a local IP address";
|
||||
}
|
||||
result.Successful = await SendEmailWithGet($"{emailUrl}/api/test?adminEmail={Url.Encode(adminEmail)}&sendEmail={sendEmail}");
|
||||
Subject = "KavitaEmail Test",
|
||||
Body = UpdatePlaceHolders(await GetEmailBody("EmailTest"), placeholders),
|
||||
ToEmails = new List<string>()
|
||||
{
|
||||
adminEmail
|
||||
}
|
||||
};
|
||||
|
||||
await SendEmail(emailOptions);
|
||||
result.Successful = true;
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
|
|
@ -82,229 +114,210 @@ public class EmailService : IEmailService
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
[Obsolete]
|
||||
public async Task<bool> IsDefaultEmailService()
|
||||
{
|
||||
return (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl))!.Value!
|
||||
.Equals(DefaultApiUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an email that has a link that will finalize an Email Change
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public async Task SendEmailChangeEmail(ConfirmationEmailDto data)
|
||||
{
|
||||
var emailLink = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl))!.Value;
|
||||
var success = await SendEmailWithPost(emailLink + "/api/account/email-change", data);
|
||||
if (!success)
|
||||
var placeholders = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
_logger.LogError("There was a critical error sending Confirmation email");
|
||||
}
|
||||
}
|
||||
new ("{{InvitingUser}}", data.InvitingUser),
|
||||
new ("{{Link}}", data.ServerConfirmationLink)
|
||||
};
|
||||
|
||||
public async Task<string> GetVersion(string emailUrl)
|
||||
{
|
||||
try
|
||||
var emailOptions = new EmailOptionsDto()
|
||||
{
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var response = await $"{emailUrl}/api/about/version"
|
||||
.WithHeader("Accept", "application/json")
|
||||
.WithHeader("User-Agent", "Kavita")
|
||||
.WithHeader("x-api-key", "MsnvA2DfQqxSK5jh")
|
||||
.WithHeader("x-kavita-version", BuildInfo.Version)
|
||||
.WithHeader("x-kavita-installId", settings.InstallId)
|
||||
.WithHeader("Content-Type", "application/json")
|
||||
.WithTimeout(TimeSpan.FromSeconds(10))
|
||||
.GetStringAsync();
|
||||
|
||||
if (!string.IsNullOrEmpty(response))
|
||||
Subject = UpdatePlaceHolders("Your email has been changed on {{InvitingUser}}'s Server", placeholders),
|
||||
Body = UpdatePlaceHolders(await GetEmailBody("EmailChange"), placeholders),
|
||||
ToEmails = new List<string>()
|
||||
{
|
||||
return response.Replace("\"", string.Empty);
|
||||
data.EmailAddress
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return null;
|
||||
await SendEmail(emailOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the email address. Does not test it actually receives mail
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsValidEmail(string email)
|
||||
{
|
||||
return new EmailAddressAttribute().IsValid(email);
|
||||
}
|
||||
|
||||
public async Task SendConfirmationEmail(ConfirmationEmailDto data)
|
||||
/// <summary>
|
||||
/// Sends an invite email to a user to setup their account
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public async Task SendInviteEmail(ConfirmationEmailDto data)
|
||||
{
|
||||
var emailLink = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl)).Value;
|
||||
var success = await SendEmailWithPost(emailLink + "/api/invite/confirm", data);
|
||||
if (!success)
|
||||
var placeholders = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
_logger.LogError("There was a critical error sending Confirmation email");
|
||||
}
|
||||
}
|
||||
new ("{{InvitingUser}}", data.InvitingUser),
|
||||
new ("{{Link}}", data.ServerConfirmationLink)
|
||||
};
|
||||
|
||||
public async Task<bool> CheckIfAccessible(string host)
|
||||
{
|
||||
// This is the only exception for using the default because we need an external service to check if the server is accessible for emails
|
||||
try
|
||||
var emailOptions = new EmailOptionsDto()
|
||||
{
|
||||
if (IsLocalIpAddress(host))
|
||||
Subject = UpdatePlaceHolders("You've been invited to join {{InvitingUser}}'s Server", placeholders),
|
||||
Body = UpdatePlaceHolders(await GetEmailBody("EmailConfirm"), placeholders),
|
||||
ToEmails = new List<string>()
|
||||
{
|
||||
_logger.LogDebug("[EmailService] Server is not accessible, using local ip");
|
||||
return false;
|
||||
data.EmailAddress
|
||||
}
|
||||
};
|
||||
|
||||
var url = DefaultApiUrl + "/api/reachable?host=" + host;
|
||||
_logger.LogDebug("[EmailService] Checking if this server is accessible for sending an email to: {Url}", url);
|
||||
return await SendEmailWithGet(url);
|
||||
}
|
||||
catch (Exception)
|
||||
await SendEmail(emailOptions);
|
||||
}
|
||||
|
||||
public Task<bool> CheckIfAccessible(string host)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public async Task<bool> SendForgotPasswordEmail(PasswordResetEmailDto dto)
|
||||
{
|
||||
var placeholders = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
new ("{{Link}}", dto.ServerConfirmationLink),
|
||||
};
|
||||
|
||||
public async Task<bool> SendMigrationEmail(EmailMigrationDto data)
|
||||
{
|
||||
var emailLink = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl)).Value;
|
||||
return await SendEmailWithPost(emailLink + "/api/invite/email-migration", data);
|
||||
}
|
||||
var emailOptions = new EmailOptionsDto()
|
||||
{
|
||||
Subject = UpdatePlaceHolders("A password reset has been requested", placeholders),
|
||||
Body = UpdatePlaceHolders(await GetEmailBody("EmailPasswordReset"), placeholders),
|
||||
ToEmails = new List<string>()
|
||||
{
|
||||
dto.EmailAddress
|
||||
}
|
||||
};
|
||||
|
||||
public async Task<bool> SendPasswordResetEmail(PasswordResetEmailDto data)
|
||||
{
|
||||
var emailLink = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl)).Value;
|
||||
return await SendEmailWithPost(emailLink + "/api/invite/email-password-reset", data);
|
||||
await SendEmail(emailOptions);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> SendFilesToEmail(SendToDto data)
|
||||
{
|
||||
if (await IsDefaultEmailService()) return false;
|
||||
var emailLink = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl)).Value;
|
||||
return await SendEmailWithFiles(emailLink + "/api/sendto", data.FilePaths, data.DestinationEmail);
|
||||
var serverSetting = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
if (!serverSetting.IsEmailSetup()) return false;
|
||||
|
||||
var emailOptions = new EmailOptionsDto()
|
||||
{
|
||||
Subject = "Send file from Kavita",
|
||||
ToEmails = new List<string>()
|
||||
{
|
||||
data.DestinationEmail
|
||||
},
|
||||
Body = await GetEmailBody("SendToDevice"),
|
||||
Attachments = data.FilePaths.ToList()
|
||||
};
|
||||
|
||||
await SendEmail(emailOptions);
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> SendEmailWithGet(string url, int timeoutSecs = 30)
|
||||
private async Task SendEmail(EmailOptionsDto userEmailOptions)
|
||||
{
|
||||
var smtpConfig = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).SmtpConfig;
|
||||
var email = new MimeMessage()
|
||||
{
|
||||
Subject = userEmailOptions.Subject,
|
||||
};
|
||||
email.From.Add(new MailboxAddress(smtpConfig.SenderDisplayName, smtpConfig.SenderAddress));
|
||||
|
||||
|
||||
var body = new BodyBuilder
|
||||
{
|
||||
HtmlBody = userEmailOptions.Body
|
||||
};
|
||||
|
||||
if (userEmailOptions.Attachments != null)
|
||||
{
|
||||
foreach (var attachment in userEmailOptions.Attachments)
|
||||
{
|
||||
await body.Attachments.AddAsync(attachment);
|
||||
}
|
||||
}
|
||||
|
||||
email.Body = body.ToMessageBody();
|
||||
|
||||
foreach (var toEmail in userEmailOptions.ToEmails)
|
||||
{
|
||||
email.To.Add(new MailboxAddress(toEmail, toEmail));
|
||||
}
|
||||
|
||||
using var smtpClient = new MailKit.Net.Smtp.SmtpClient();
|
||||
smtpClient.Timeout = 20000;
|
||||
var ssl = smtpConfig.EnableSsl ? SecureSocketOptions.Auto : SecureSocketOptions.None;
|
||||
|
||||
await smtpClient.ConnectAsync(smtpConfig.Host, smtpConfig.Port, ssl);
|
||||
if (!string.IsNullOrEmpty(smtpConfig.UserName) && !string.IsNullOrEmpty(smtpConfig.Password))
|
||||
{
|
||||
await smtpClient.AuthenticateAsync(smtpConfig.UserName, smtpConfig.Password);
|
||||
}
|
||||
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;
|
||||
|
||||
try
|
||||
{
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var response = await (url)
|
||||
.WithHeader("Accept", "application/json")
|
||||
.WithHeader("User-Agent", "Kavita")
|
||||
.WithHeader("x-api-key", "MsnvA2DfQqxSK5jh")
|
||||
.WithHeader("x-kavita-version", BuildInfo.Version)
|
||||
.WithHeader("x-kavita-installId", settings.InstallId)
|
||||
.WithHeader("Content-Type", "application/json")
|
||||
.WithTimeout(TimeSpan.FromSeconds(timeoutSecs))
|
||||
.GetStringAsync();
|
||||
|
||||
if (!string.IsNullOrEmpty(response) && bool.Parse(response))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
await smtpClient.SendAsync(email);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new KavitaException(ex.Message);
|
||||
_logger.LogError(ex, "There was an issue sending the email");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await smtpClient.DisconnectAsync(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private async Task<bool> SendEmailWithPost(string url, object data, int timeoutSecs = 30)
|
||||
private async Task<string> GetTemplatePath(string templateName)
|
||||
{
|
||||
try
|
||||
if ((await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).SmtpConfig.CustomizedTemplates)
|
||||
{
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var response = await (url)
|
||||
.WithHeader("Accept", "application/json")
|
||||
.WithHeader("User-Agent", "Kavita")
|
||||
.WithHeader("x-api-key", "MsnvA2DfQqxSK5jh")
|
||||
.WithHeader("x-kavita-version", BuildInfo.Version)
|
||||
.WithHeader("x-kavita-installId", settings.InstallId)
|
||||
.WithHeader("Content-Type", "application/json")
|
||||
.WithTimeout(TimeSpan.FromSeconds(timeoutSecs))
|
||||
.PostJsonAsync(data);
|
||||
var templateDirectory = Path.Join(_directoryService.CustomizedTemplateDirectory, TemplatePath);
|
||||
var fullName = string.Format(templateDirectory, templateName);
|
||||
if (_directoryService.FileSystem.File.Exists(fullName)) return fullName;
|
||||
_logger.LogError("Customized Templates is on, but template {TemplatePath} is missing", fullName);
|
||||
}
|
||||
|
||||
if (response.StatusCode != StatusCodes.Status200OK)
|
||||
return string.Format(Path.Join(_directoryService.TemplateDirectory, TemplatePath), templateName);
|
||||
}
|
||||
|
||||
private async Task<string> GetEmailBody(string templateName)
|
||||
{
|
||||
var templatePath = await GetTemplatePath(templateName);
|
||||
|
||||
var body = await File.ReadAllTextAsync(templatePath);
|
||||
return body;
|
||||
}
|
||||
|
||||
private static string UpdatePlaceHolders(string text, IList<KeyValuePair<string, string>> keyValuePairs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text) || keyValuePairs == null) return text;
|
||||
|
||||
foreach (var (key, value) in keyValuePairs)
|
||||
{
|
||||
if (text.Contains(key))
|
||||
{
|
||||
var errorMessage = await response.GetStringAsync();
|
||||
throw new KavitaException(errorMessage);
|
||||
text = text.Replace(key, value);
|
||||
}
|
||||
}
|
||||
catch (FlurlHttpException ex)
|
||||
{
|
||||
_logger.LogError(ex, "There was an exception when interacting with Email Service");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
private async Task<bool> SendEmailWithFiles(string url, IEnumerable<string> filePaths, string destEmail, int timeoutSecs = 300)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var response = await (url)
|
||||
.WithHeader("User-Agent", "Kavita")
|
||||
.WithHeader("x-api-key", "MsnvA2DfQqxSK5jh")
|
||||
.WithHeader("x-kavita-version", BuildInfo.Version)
|
||||
.WithHeader("x-kavita-installId", settings.InstallId)
|
||||
.WithTimeout(timeoutSecs)
|
||||
.AllowHttpStatus("4xx")
|
||||
.PostMultipartAsync(mp =>
|
||||
{
|
||||
mp.AddString("email", destEmail);
|
||||
var index = 1;
|
||||
foreach (var filepath in filePaths)
|
||||
{
|
||||
mp.AddFile("file" + index, filepath, _downloadService.GetContentTypeFromFile(filepath));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (response.StatusCode != StatusCodes.Status200OK)
|
||||
{
|
||||
var errorMessage = await response.GetStringAsync();
|
||||
throw new KavitaException(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (FlurlHttpException ex)
|
||||
{
|
||||
_logger.LogError(ex, "There was an exception when sending Email for SendTo");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsLocalIpAddress(string url)
|
||||
{
|
||||
var host = url.Split(':')[0];
|
||||
try
|
||||
{
|
||||
// get host IP addresses
|
||||
var hostIPs = Dns.GetHostAddresses(host);
|
||||
// get local IP addresses
|
||||
var localIPs = Dns.GetHostAddresses(Dns.GetHostName());
|
||||
|
||||
// test if any host IP equals to any local IP or to localhost
|
||||
foreach (var hostIp in hostIPs)
|
||||
{
|
||||
// is localhost
|
||||
if (IPAddress.IsLoopback(hostIp)) return true;
|
||||
// is local address
|
||||
if (localIPs.Contains(hostIp))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,6 +244,9 @@ public class Startup
|
|||
await MigrateSmartFilterEncoding.Migrate(unitOfWork, dataContext, logger);
|
||||
await MigrateLibrariesToHaveAllFileTypes.Migrate(unitOfWork, dataContext, logger);
|
||||
|
||||
// v0.7.14
|
||||
await MigrateEmailTemplates.Migrate(directoryService, logger);
|
||||
|
||||
// Update the version in the DB after all migrations are run
|
||||
var installVersion = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion);
|
||||
installVersion.Value = BuildInfo.Version.ToString();
|
||||
|
|
|
|||
348
API/config/templates/EmailChange.html
Normal file
348
API/config/templates/EmailChange.html
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Event - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> Your account's email has been updated on {{InvitingUser}}'s Kavita instance. Click the button to validate your email. </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">Email Change Update</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Your account's email has been updated on {{InvitingUser}}'s Kavita instance.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Please click the following link to validate your email change.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||
<!-- Button : BEGIN -->
|
||||
<center>
|
||||
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow" style="text-align: center;">
|
||||
<tr>
|
||||
<td style="border-radius: 50px; background: #153643; text-align: center;" class="button-td">
|
||||
<a href="{{Link}}" style="background: #153643; border: 15px solid #153643; font-family: 'Montserrat', sans-serif; font-size: 14px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 50px; font-weight: bold;" class="button-a"> <span style="color:#ffffff;" class="button-link"> CONFIRM EMAIL </span> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<!-- Button : END -->
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If the button above does not work, please find the link here: <a style="color:inherit;margin: 0;width: 100%;word-break: break-all;" href="{{Link}}">{{Link}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
348
API/config/templates/EmailConfirm.html
Normal file
348
API/config/templates/EmailConfirm.html
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Event - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> You have been invited to {{InvitingUser}}'s Kavita instance. Click the button to accept the invite. </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">You've Been Invited</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">You have been invited to {{InvitingUser}}'s Kavita instance.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Please click the following link to setup an account for yourself and start reading.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||
<!-- Button : BEGIN -->
|
||||
<center>
|
||||
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow" style="text-align: center;">
|
||||
<tr>
|
||||
<td style="border-radius: 50px; background: #153643; text-align: center;" class="button-td">
|
||||
<a href="{{Link}}" style="background: #153643; border: 15px solid #153643; font-family: 'Montserrat', sans-serif; font-size: 14px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 50px; font-weight: bold;" class="button-a"> <span style="color:#ffffff;" class="button-link"> ACCEPT INVITE </span> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<!-- Button : END -->
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If the button above does not work, please find the link here: <a style="color:inherit;margin: 0;width: 100%;word-break: break-all;" href="{{Link}}">{{Link}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
343
API/config/templates/EmailMigration.html
Normal file
343
API/config/templates/EmailMigration.html
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Kavita - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap);
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> Email confirmation is required for continued access. Click the button to confirm your email. </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">Confirmation Required</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Please click the following link to confirm your email for {{User}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||
<!-- Button : BEGIN -->
|
||||
<center>
|
||||
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow" style="text-align: center;">
|
||||
<tr>
|
||||
<td style="border-radius: 50px; background: #153643; text-align: center;" class="button-td">
|
||||
<a href="{{Link}}" style="background: #153643; border: 15px solid #153643; font-family: 'Montserrat', sans-serif; font-size: 14px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 50px; font-weight: bold;" class="button-a"> <span style="color:#ffffff;" class="button-link"> CONFIRM </span> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<!-- Button : END -->
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If the button above does not work, please find the link here: <a style="color:inherit;margin: 0;width: 100%;word-break: break-all;" href="{{Link}}">{{Link}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
348
API/config/templates/EmailPasswordReset.html
Normal file
348
API/config/templates/EmailPasswordReset.html
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Kavita - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap);
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> Email confirmation is required for continued access. Click the button to confirm your email. </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">Forgot your password?</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">That's okay, it happens! Click on the button below to reset your password.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||
<!-- Button : BEGIN -->
|
||||
<center>
|
||||
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow" style="text-align: center;">
|
||||
<tr>
|
||||
<td style="border-radius: 50px; background: #153643; text-align: center;" class="button-td">
|
||||
<a href="{{Link}}" style="background: #153643; border: 15px solid #153643; font-family: 'Montserrat', sans-serif; font-size: 14px; line-height: 1.1; text-align: center; text-decoration: none; display: block; border-radius: 50px; font-weight: bold;" class="button-a"> <span style="color:#ffffff;" class="button-link"> RESET YOUR PASSWORD </span> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<!-- Button : END -->
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 0px 20px 0px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If you did not perform this action, ignore this email.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 12px; line-height: 20px;">
|
||||
<p style="margin: 0;">If the button above does not work, please find the link here: <a style="color:inherit;margin: 0;width: 100%;word-break: break-all;" href="{{Link}}">{{Link}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
325
API/config/templates/EmailTest.html
Normal file
325
API/config/templates/EmailTest.html
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Event - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;">
|
||||
This is a Test Email
|
||||
</div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">This is a Test Email</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">If you've received this email, your KavitaEmail is setup</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
323
API/config/templates/SendToDevice.html
Normal file
323
API/config/templates/SendToDevice.html
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>Event - [Plain HTML]</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
<!-- Web Font / @font-face : BEGIN -->
|
||||
<!-- NOTE: If web fonts are not required, lines 10 - 27 can be safely removed. -->
|
||||
<!-- Desktop Outlook chokes on web font references and defaults to Times New Roman, so we force a safe fallback font. -->
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!-- All other clients get the webfont reference; some will render the font and others will silently fail to the fallbacks. More on that here: http://stylecampaign.com/blog/2015/02/webfont-support-in-email/ -->
|
||||
<!--[if !mso]><!-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
|
||||
<!--<![endif]-->
|
||||
<!-- Web Font / @font-face : END -->
|
||||
<!-- CSS Reset -->
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@500;700&display=swap');
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
/* What it does: Fixes webkit padding issue. Fix for Yahoo mail table alignment bug. Applies table-layout to the first 2 tables then removes for anything nested deeper. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
}
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.x-gmail-data-detectors,
|
||||
/* Gmail */
|
||||
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
/* What it does: Prevents Gmail from displaying an download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
/* What it does: Prevents underlining the button text in Windows 10 */
|
||||
|
||||
.button-link {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* Thanks to Eric Lepetit @ericlepetitsf) for help troubleshooting */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
/* iPhone 6 and 6+ */
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Progressive Enhancements -->
|
||||
<style>
|
||||
/* What it does: Hover styles for buttons */
|
||||
|
||||
.button-td,
|
||||
.button-a {
|
||||
transition: all 100ms ease-in;
|
||||
}
|
||||
|
||||
.button-td:hover,
|
||||
.button-a:hover {
|
||||
background: #000000 !important;
|
||||
border-color: #000000 !important;
|
||||
color: white !important;
|
||||
}
|
||||
/* Media Queries */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
/* What it does: Forces elements to resize to the full width of their container. Useful for resizing images beyond their max-width. */
|
||||
.fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
/* What it does: Forces table cells into full-width rows. */
|
||||
.stack-column,
|
||||
.stack-column-center {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
direction: ltr !important;
|
||||
}
|
||||
/* And center justify these ones. */
|
||||
.stack-column-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
/* What it does: Generic utility class for centering. Useful for images, buttons, and nested tables. */
|
||||
.center-on-narrow {
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
table.center-on-narrow {
|
||||
display: inline-block !important;
|
||||
}
|
||||
/* What it does: Adjust typography on small screens to improve readability */
|
||||
.email-container p {
|
||||
font-size: 17px !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body width="100%" bgcolor="#F1F1F1" style="margin: 0; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #F1F1F1; text-align: left;">
|
||||
<!-- Visually Hidden Preheader Text : BEGIN -->
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;"> You've been sent a file from Kavita! </div>
|
||||
<!-- Visually Hidden Preheader Text : END -->
|
||||
<!--
|
||||
Set the email width. Defined in two places:
|
||||
1. max-width for all clients except Desktop Windows Outlook, allowing the email to squish on narrow but never go wider than 680px.
|
||||
2. MSO tags for Desktop Windows Outlook enforce a 680px width.
|
||||
Note: The Fluid and Responsive templates have a different width (600px). The hybrid grid is more "fragile", and I've found that 680px is a good width. Change with caution.
|
||||
-->
|
||||
<div style="max-width: 680px; margin: auto;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="680" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<!-- Email Body : BEGIN -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 680px;" class="email-container">
|
||||
<!-- HEADER : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#4AC694">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="margin-left: -10px;padding: 10px 40px 10px 40px; text-align: center;"> <img src="https://www.kavitareader.com/img/email/logo-256.png" alt="kavita_logo" width="75" style="height:auto;display:inline-block;vertical-align:middle;" />
|
||||
<div style="min-height:75px;line-height:75px;display:inline-block;vertical-align:middle;color:#fff;font-family: 'Spartan', sans-serif;font-size:2rem;font-weight:700;">Kavita</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HEADER : END -->
|
||||
<!-- HERO : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#fff" align="center" valign="top" style="text-align: center; background-position: center center !important; background-size: cover !important;">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:680px; height:380px; background-position: center center !important;">
|
||||
<v:fill type="tile" src="background.png" color="#222222" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<div>
|
||||
<!--[if mso]>
|
||||
<table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="500">
|
||||
<![endif]-->
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" width="100%" style="max-width:500px; margin: auto;">
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">You sent a file from Kavita</h1> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="text-align: center; padding: 10px 20px 15px 20px; font-family: sans-serif; font-size: 18px; line-height: 20px;">
|
||||
<p style="margin: 0;">Please find attached the file(s) you've sent.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20" style="font-size:20px; line-height:20px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- HERO : END -->
|
||||
<!-- SOCIAL : BEGIN -->
|
||||
<tr>
|
||||
<td bgcolor="#292828">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 15px 30px; text-align: center;">
|
||||
<table align="center" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://discord.gg/b52wT37kt7"><img style="width:25px" src="https://www.kavitareader.com/img/email/discord-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Discord"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://www.reddit.com/r/KavitaManga/"><img style="width:25px" src="https://www.kavitareader.com/img/email/reddit-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Reddit"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://github.com/Kareadita/Kavita/"><img style="width:25px" src="https://www.kavitareader.com/img/email/github-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Github"></a>
|
||||
</td>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<a href="https://opencollective.com/kavita"><img style="width:25px" src="https://www.kavitareader.com/img/email/open-collective-white.png" width="" height="" style="margin:0; padding:0; border:none; display:block;" border="0" alt="Open Collective"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- SOCIAL : END -->
|
||||
</table>
|
||||
<!-- Email Body : END -->
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue