mirror of https://github.com/abpframework/abp.git
committed by
GitHub
41 changed files with 656 additions and 225 deletions
@ -0,0 +1,16 @@ |
|||
using Volo.Abp.Emailing.Templates.VirtualFiles; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class DefaultEmailTemplateProvider : EmailTemplateDefinitionProvider |
|||
{ |
|||
public override void Define(IEmailTemplateDefinitionContext context) |
|||
{ |
|||
context.Add(new EmailTemplateDefinition(StandardEmailTemplates.DefaultLayout, isLayout: true, layout: null) |
|||
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Layout")); |
|||
|
|||
context.Add(new EmailTemplateDefinition(StandardEmailTemplates.SimpleMessage) |
|||
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Message")); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class EmailTemplateContributorList : List<IEmailTemplateContributor> |
|||
{ |
|||
public string GetOrNull(string cultureName) |
|||
{ |
|||
foreach (var contributor in this.AsQueryable().Reverse()) |
|||
{ |
|||
var templateString = contributor.GetOrNull(cultureName); |
|||
if (templateString != null) |
|||
{ |
|||
return templateString; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class EmailTemplateDefinitionContext : IEmailTemplateDefinitionContext |
|||
{ |
|||
protected Dictionary<string, EmailTemplateDefinition> EmailTemplates { get; } |
|||
|
|||
public EmailTemplateDefinitionContext(Dictionary<string, EmailTemplateDefinition> emailTemplates) |
|||
{ |
|||
EmailTemplates = emailTemplates; |
|||
} |
|||
|
|||
public virtual EmailTemplateDefinition GetOrNull(string name) |
|||
{ |
|||
return EmailTemplates.GetOrDefault(name); |
|||
} |
|||
|
|||
public virtual IReadOnlyList<EmailTemplateDefinition> GetAll() |
|||
{ |
|||
return EmailTemplates.Values.ToImmutableList(); |
|||
} |
|||
|
|||
public virtual void Add(params EmailTemplateDefinition[] definitions) |
|||
{ |
|||
if (definitions.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var definition in definitions) |
|||
{ |
|||
EmailTemplates[definition.Name] = definition; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
using System.Linq; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class EmailTemplateDefinitionManager : IEmailTemplateDefinitionManager, ISingletonDependency |
|||
{ |
|||
protected Lazy<IDictionary<string, EmailTemplateDefinition>> EmailTemplateDefinitions { get; } |
|||
|
|||
protected EmailTemplateOptions Options { get; } |
|||
|
|||
protected IServiceProvider ServiceProvider { get; } |
|||
|
|||
public EmailTemplateDefinitionManager( |
|||
IOptions<EmailTemplateOptions> options, |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
Options = options.Value; |
|||
|
|||
EmailTemplateDefinitions = |
|||
new Lazy<IDictionary<string, EmailTemplateDefinition>>(CreateEmailTemplateDefinitions, true); |
|||
} |
|||
|
|||
public virtual EmailTemplateDefinition Get(string name) |
|||
{ |
|||
Check.NotNull(name, nameof(name)); |
|||
|
|||
var template = GetOrNull(name); |
|||
|
|||
if (template == null) |
|||
{ |
|||
throw new AbpException("Undefined template: " + name); |
|||
} |
|||
|
|||
return template; |
|||
} |
|||
|
|||
public virtual IReadOnlyList<EmailTemplateDefinition> GetAll() |
|||
{ |
|||
return EmailTemplateDefinitions.Value.Values.ToImmutableList(); |
|||
} |
|||
|
|||
public virtual EmailTemplateDefinition GetOrNull(string name) |
|||
{ |
|||
return EmailTemplateDefinitions.Value.GetOrDefault(name); |
|||
} |
|||
|
|||
protected virtual IDictionary<string, EmailTemplateDefinition> CreateEmailTemplateDefinitions() |
|||
{ |
|||
var templates = new Dictionary<string, EmailTemplateDefinition>(); |
|||
|
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var providers = Options |
|||
.DefinitionProviders |
|||
.Select(p => scope.ServiceProvider.GetRequiredService(p) as IEmailTemplateDefinitionProvider) |
|||
.ToList(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
provider.Define(new EmailTemplateDefinitionContext(templates)); |
|||
} |
|||
} |
|||
|
|||
return templates; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public abstract class EmailTemplateDefinitionProvider : IEmailTemplateDefinitionProvider, ITransientDependency |
|||
{ |
|||
public abstract void Define(IEmailTemplateDefinitionContext context); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class EmailTemplateInitializationContext |
|||
{ |
|||
public EmailTemplateDefinition EmailTemplateDefinition { get; } |
|||
|
|||
public IServiceProvider ServiceProvider { get; } |
|||
|
|||
public EmailTemplateInitializationContext(EmailTemplateDefinition emailTemplateDefinition, |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
EmailTemplateDefinition = emailTemplateDefinition; |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
} |
|||
} |
|||
@ -1,26 +1,18 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Emailing.Templates.Virtual; |
|||
using Volo.Abp.Collections; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class EmailTemplateOptions |
|||
{ |
|||
public List<IEmailTemplateProviderContributor> Providers { get; } |
|||
|
|||
public EmailTemplateDefinitionDictionary Templates { get; } |
|||
|
|||
public string DefaultLayout { get; set; } |
|||
|
|||
public ITypeList<IEmailTemplateDefinitionProvider> DefinitionProviders { get; } |
|||
|
|||
public EmailTemplateOptions() |
|||
{ |
|||
Providers = new List<IEmailTemplateProviderContributor> |
|||
{ |
|||
new VirtualFileEmailTemplateProviderContributor() |
|||
}; |
|||
|
|||
Templates = new EmailTemplateDefinitionDictionary(); |
|||
|
|||
DefaultLayout = StandardEmailTemplates.DefaultLayout; |
|||
|
|||
DefinitionProviders = new TypeList<IEmailTemplateDefinitionProvider>(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class EmailTemplateProviderContributorContext : IServiceProviderAccessor |
|||
{ |
|||
public string Name { get; } |
|||
|
|||
public IServiceProvider ServiceProvider { get; } |
|||
|
|||
public EmailTemplate Template { get; set; } |
|||
|
|||
public EmailTemplateProviderContributorContext(string name, IServiceProvider serviceProvider) |
|||
{ |
|||
Name = name; |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public interface IEmailTemplateContributor |
|||
{ |
|||
void Initialize(EmailTemplateInitializationContext context); |
|||
|
|||
string GetOrNull(string cultureName); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public interface IEmailTemplateDefinitionContext |
|||
{ |
|||
EmailTemplateDefinition GetOrNull(string name); |
|||
|
|||
void Add(params EmailTemplateDefinition[] definitions); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public interface IEmailTemplateDefinitionManager |
|||
{ |
|||
[NotNull] |
|||
EmailTemplateDefinition Get([NotNull] string name); |
|||
|
|||
IReadOnlyList<EmailTemplateDefinition> GetAll(); |
|||
|
|||
EmailTemplateDefinition GetOrNull(string name); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public interface IEmailTemplateDefinitionProvider |
|||
{ |
|||
void Define(IEmailTemplateDefinitionContext context); |
|||
} |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public interface IEmailTemplateProviderContributor |
|||
{ |
|||
Task ProvideAsync(EmailTemplateProviderContributorContext contributorContext); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public interface ITemplateRender |
|||
{ |
|||
Task<string> RenderAsync(string template, object model = null); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System.Threading.Tasks; |
|||
using Scriban; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates |
|||
{ |
|||
public class TemplateRender : ITemplateRender, ITransientDependency |
|||
{ |
|||
public async Task<string> RenderAsync(string template, object model = null) |
|||
{ |
|||
var scribanTemplate = Template.Parse(template); |
|||
return await scribanTemplate.RenderAsync(model); |
|||
} |
|||
} |
|||
} |
|||
@ -1,16 +0,0 @@ |
|||
namespace Volo.Abp.Emailing.Templates.Virtual |
|||
{ |
|||
public static class EmailTemplateDefinitionExtensions |
|||
{ |
|||
public static EmailTemplateDefinition SetVirtualFilePath(this EmailTemplateDefinition emailTemplateDefinition, string path) |
|||
{ |
|||
emailTemplateDefinition[VirtualFileEmailTemplateProviderContributor.VirtualFilePathKey] = path; |
|||
return emailTemplateDefinition; |
|||
} |
|||
|
|||
public static string GetVirtualFilePathOrNull(this EmailTemplateDefinition emailTemplateDefinition) |
|||
{ |
|||
return emailTemplateDefinition[VirtualFileEmailTemplateProviderContributor.VirtualFilePathKey] as string; |
|||
} |
|||
} |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates.Virtual |
|||
{ |
|||
public class VirtualFileEmailTemplateOptions |
|||
{ |
|||
public IDictionary<string, string> Templates { get; } |
|||
|
|||
public VirtualFileEmailTemplateOptions() |
|||
{ |
|||
Templates = new Dictionary<string, string>(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,61 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.FileProviders; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates.Virtual |
|||
{ |
|||
public class VirtualFileEmailTemplateProviderContributor : IEmailTemplateProviderContributor |
|||
{ |
|||
public const string VirtualFilePathKey = "VirtualFilePath"; |
|||
|
|||
public Task ProvideAsync(EmailTemplateProviderContributorContext contributorContext) |
|||
{ |
|||
var templateDefinition = FindTemplateDefinition(contributorContext); |
|||
if (templateDefinition == null) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
var fileInfo = FindVirtualFileInfo(contributorContext, templateDefinition); |
|||
if (fileInfo == null) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
contributorContext.Template = new EmailTemplate(fileInfo.ReadAsString(), templateDefinition); |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual EmailTemplateDefinition FindTemplateDefinition(EmailTemplateProviderContributorContext contributorContext) |
|||
{ |
|||
return contributorContext |
|||
.ServiceProvider |
|||
.GetRequiredService<IOptions<EmailTemplateOptions>>() |
|||
.Value |
|||
.Templates |
|||
.GetOrDefault(contributorContext.Name); |
|||
} |
|||
|
|||
protected virtual IFileInfo FindVirtualFileInfo(EmailTemplateProviderContributorContext contributorContext, EmailTemplateDefinition templateDefinition) |
|||
{ |
|||
var virtualFilePath = templateDefinition?.GetVirtualFilePathOrNull(); |
|||
if (virtualFilePath == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var virtualFileProvider = contributorContext.ServiceProvider.GetRequiredService<IVirtualFileProvider>(); |
|||
|
|||
var fileInfo = virtualFileProvider.GetFileInfo(virtualFilePath); |
|||
if (fileInfo?.Exists != true) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return fileInfo; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
namespace Volo.Abp.Emailing.Templates.VirtualFiles |
|||
{ |
|||
public static class EmailTemplateDefinitionExtensions |
|||
{ |
|||
public static EmailTemplateDefinition AddTemplateVirtualFile( |
|||
this EmailTemplateDefinition emailTemplateDefinition, string path) |
|||
{ |
|||
emailTemplateDefinition.Contributors.Add(new SingleVirtualFileEmailTemplateContributor(path)); |
|||
return emailTemplateDefinition; |
|||
} |
|||
|
|||
public static EmailTemplateDefinition AddTemplateVirtualFiles( |
|||
this EmailTemplateDefinition emailTemplateDefinition, string path) |
|||
{ |
|||
emailTemplateDefinition.Contributors.Add(new MultipleVirtualFilesEmailTemplateContributor(path)); |
|||
return emailTemplateDefinition; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.FileProviders; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates.VirtualFiles |
|||
{ |
|||
public class MultipleVirtualFilesEmailTemplateContributor : IEmailTemplateContributor |
|||
{ |
|||
private readonly string _virtualPath; |
|||
|
|||
private IVirtualFileProvider _virtualFileProvider; |
|||
|
|||
private Dictionary<string, string> _templateDictionary; |
|||
|
|||
private readonly object _syncObj = new object(); |
|||
|
|||
public MultipleVirtualFilesEmailTemplateContributor(string virtualPath) |
|||
{ |
|||
_virtualPath = virtualPath; |
|||
} |
|||
|
|||
public void Initialize(EmailTemplateInitializationContext context) |
|||
{ |
|||
_virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>(); |
|||
} |
|||
|
|||
public string GetOrNull(string cultureName) |
|||
{ |
|||
return GetTemplateDictionary().GetOrDefault(cultureName); |
|||
} |
|||
|
|||
private Dictionary<string, string> GetTemplateDictionary() |
|||
{ |
|||
var dictionaries = _templateDictionary; |
|||
if (dictionaries != null) |
|||
{ |
|||
return dictionaries; |
|||
} |
|||
|
|||
lock (_syncObj) |
|||
{ |
|||
dictionaries = _templateDictionary; |
|||
if (dictionaries != null) |
|||
{ |
|||
return dictionaries; |
|||
} |
|||
|
|||
_templateDictionary = new Dictionary<string, string>(); |
|||
foreach (var file in _virtualFileProvider.GetDirectoryContents(_virtualPath)) |
|||
{ |
|||
if (file.IsDirectory) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
// TODO: How to normalize file names?
|
|||
_templateDictionary.Add(file.Name.RemovePostFix(".tpl"), file.ReadAsString()); |
|||
} |
|||
|
|||
dictionaries = _templateDictionary; |
|||
} |
|||
|
|||
return dictionaries; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.FileProviders; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace Volo.Abp.Emailing.Templates.VirtualFiles |
|||
{ |
|||
public class SingleVirtualFileEmailTemplateContributor : IEmailTemplateContributor |
|||
{ |
|||
private readonly string _virtualPath; |
|||
|
|||
private IVirtualFileProvider _virtualFileProvider; |
|||
|
|||
public SingleVirtualFileEmailTemplateContributor(string virtualPath) |
|||
{ |
|||
_virtualPath = virtualPath; |
|||
} |
|||
|
|||
public void Initialize(EmailTemplateInitializationContext context) |
|||
{ |
|||
_virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>(); |
|||
} |
|||
|
|||
public string GetOrNull(string cultureName) |
|||
{ |
|||
var file = _virtualFileProvider.GetFileInfo(_virtualPath); |
|||
if (file == null || !file.Exists || file.IsDirectory) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return file.ReadAsString(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Shouldly; |
|||
using Volo.Abp.Emailing.Templates; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.Emailing |
|||
{ |
|||
public class EmailTemplateRender_Tests : AbpIntegratedTest<AbpEmailingTestModule> |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
|
|||
private readonly ITemplateRender _templateRender; |
|||
|
|||
public EmailTemplateRender_Tests() |
|||
{ |
|||
_templateRender = GetRequiredService<ITemplateRender>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task RenderAsync() |
|||
{ |
|||
var template = "Hello {{email}} {{ for order in orders }}{{ order.id }}:{{ order.name }},{{ end }}"; |
|||
|
|||
var model = new ModelClass |
|||
{ |
|||
Email = "john@abp.io", |
|||
Orders = new List<ModelClass.Order> |
|||
{ |
|||
new ModelClass.Order |
|||
{ |
|||
Id = "1", |
|||
Name = "iphone" |
|||
}, |
|||
new ModelClass.Order |
|||
{ |
|||
Id = "2", |
|||
Name = "ipad" |
|||
} |
|||
} |
|||
}; |
|||
|
|||
var result = await _templateRender.RenderAsync(template, model); |
|||
result.ShouldBe("Hello john@abp.io 1:iphone,2:ipad,"); |
|||
} |
|||
|
|||
public class ModelClass |
|||
{ |
|||
public string Email { get; set; } |
|||
|
|||
public List<Order> Orders { get; set; } |
|||
|
|||
public class Order |
|||
{ |
|||
public string Id { get; set; } |
|||
|
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Volo.Abp.Emailing.Localization |
|||
{ |
|||
public class AbpEmailingTestResource |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"hello": "hello" |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
{ |
|||
"culture": "tr", |
|||
"texts": { |
|||
"hello": "Merhaba" |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using Volo.Abp.Emailing.Localization; |
|||
using Volo.Abp.Emailing.Templates; |
|||
using Volo.Abp.Emailing.Templates.VirtualFiles; |
|||
|
|||
namespace Volo.Abp.Emailing |
|||
{ |
|||
public class TestEmailTemplateProvider : EmailTemplateDefinitionProvider |
|||
{ |
|||
public override void Define(IEmailTemplateDefinitionContext context) |
|||
{ |
|||
var template1 = new EmailTemplateDefinition("template1", defaultCultureName: "en", layout: null) |
|||
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/TestTemplates/Template1"); |
|||
context.Add(template1); |
|||
|
|||
var template2 = new EmailTemplateDefinition("template2", layout: StandardEmailTemplates.DefaultLayout) |
|||
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/TestTemplates/Template2"); |
|||
context.Add(template2); |
|||
|
|||
var template3 = new EmailTemplateDefinition("template3", layout: null, singleTemplateFile: true, localizationResource: typeof(AbpEmailingTestResource)) |
|||
.AddTemplateVirtualFile("/Volo/Abp/Emailing/TestTemplates/Template3/Template.tpl"); |
|||
context.Add(template3); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
Please confirm your email address by clicking the link below. |
|||
We may need to send you critical information about our service and it is important that we have an accurate email address. |
|||
|
|||
<a href="#">Confirm email address</a> |
|||
@ -0,0 +1,4 @@ |
|||
Lütfen aşağıdaki bağlantıya tıklayarak e-posta adresinizi onaylayın. |
|||
Size hizmetimizle ilgili kritik bilgileri göndermemiz gerekebilir ve doğru bir e-posta adresimizin olması önemlidir. |
|||
|
|||
<a href="#">E-posta adresini onayla</a> |
|||
@ -0,0 +1,4 @@ |
|||
Please confirm your email address by clicking the link below. |
|||
We may need to send you critical information about our service and it is important that we have an accurate email address. |
|||
|
|||
<a href="#">Confirm email address</a> |
|||
@ -0,0 +1 @@ |
|||
{{#L:hello}} Abp |
|||
@ -1,9 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
</head> |
|||
<body> |
|||
This is a test template! |
|||
</body> |
|||
</html> |
|||
Loading…
Reference in new issue