Skip to content

Commit

Permalink
Simplify API (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
hbulens authored Mar 22, 2024
1 parent ab8d5fe commit a7dc0b5
Show file tree
Hide file tree
Showing 70 changed files with 1,094 additions and 806 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
*.vs
TestResults
**/**.DotSettings.user
src/packages
src/packages
**.trx
*.cobertura*.xml
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ decisions when appropriate.

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 Dime Software
Copyright (c) 2024 Dime Software

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
93 changes: 55 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@
<h1 align="center"> Facteur </h1>

<p align="center">
<img src="https://img.shields.io/azure-devops/build/dimesoftware/utilities/177?style=flat-square" />
<img src='https://img.shields.io/azure-devops/tests/dimesoftware/utilities/177?compact_message&style=flat-square' />
<img src="https://dev.azure.com/dimesoftware/Utilities/_apis/build/status/dimenics.facteur?branchName=master" />
<img src="https://img.shields.io/nuget/v/facteur?style=flat-square" />
<img src="https://img.shields.io/azure-devops/coverage/dimesoftware/utilities/177?style=flat-square" />
<a href="https://codeclimate.com/github/dimesoftware/facteur/maintainability"><img src="https://api.codeclimate.com/v1/badges/7d604cce096ee94210a6/maintainability" /></a>
<img src="https://img.shields.io/badge/License-MIT-brightgreen.svg?style=flat-square" />
<img src="https://img.shields.io/azure-devops/coverage/dimesoftware/utilities/177" />
<img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" />
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" />
<a href="https://github.com/dimesoftware/facteur/discussions">
<img src="https://img.shields.io/badge/chat-discussions-brightgreen?style=flat-square">
</a>
<a href="https://gitter.im/facteur-dotnet/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge"><img src="https://img.shields.io/badge/chat-on%20gitter-brightgreen.svg?style=flat-square" /></a>

</p>

Facteur (French for mailman) is a library for sending e-mails in .NET. Its modular approach allows you to assemble a mail system rather than having to use a take-it-or-leave it service.
Facteur (French for mailman) is a library for sending emails in .NET. Its modular approach allows you to assemble a mail system rather than having to use a take-it-or-leave it service.

Check out the **[📚 docs »](https://dimesoftware.github.io/facteur/)** for more info.

Expand All @@ -35,13 +32,13 @@ There are a few moving parts:
- Template providers
- Endpoints

**Composers** enable you to create an e-mail request, which contains the e-mail variables like subject, body and the e-mail addresses to send the mail to.
**Composers** enable you to create an email request, which contains the email variables like subject, body and the email addresses to send the mail to.

**Compilers** are a part of the e-mail composition in that it allows to fetch a template and populate the e-mail body with data from a custom view model.
**Compilers** are a part of the email composition in that it allows to fetch a template and populate the email body with data from a custom view model.

The templates can be stored anywhere. By default they are stored in the folder where the application is hosted but it can also be retrieved from an Azure blob, FTP drive, etc. Using **template providers** and **resolvers**, you can write your own logic to fetch the right template for the job.

Lastly and obviously, there are the various mail services, also known as **endpoints** in Facteur. E-mails can be sent with good old SMTP, Microsoft Graph API, SendGrid, etc.
Lastly and obviously, there are the various mail services, also known as **endpoints** in Facteur. emails can be sent with good old SMTP, Microsoft Graph API, SendGrid, etc.

## Installation

Expand All @@ -57,12 +54,11 @@ Next it is up to you to decide which *endpoint* you want to use:
| SMTP | `dotnet add package Facteur.Smtp` |
| SendGrid | `dotnet add package Facteur.SendGrid` |

Next, you should decide which *compiler* to use to generate the body of your e-mail. The following packages are available:
Next, you should decide which *compiler* to use to generate the body of your email. The following packages are available:

| Resolvers | Command |
| ----------- | ---------------------------------------------- |
| RazorEngine | `dotnet add package Facteur.Compilers.Razor` |
| Scriban | `dotnet add package Facteur.Compilers.Scriban` |
| Resolvers | Command |
| --------- | ---------------------------------------------- |
| Scriban | `dotnet add package Facteur.Compilers.Scriban` |

You also have a choice in the template providers. Templates can be stored on a regular file drive but it might as well be stored on a blob on Azure.

Expand All @@ -82,33 +78,59 @@ Finally, there are some ancillary packages:
| ------------ | ----------------------------------------------------------- |
| .NET Core DI | `dotnet add package Facteur.Extensions.DependencyInjection` |

## Configuration

With .NET's dependency injection, hooking up the mailer can be done by adding a few lines to the Startup class:

```csharp
serviceCollection.AddFacteur(x =>
{
x.WithMailer(y => new SmtpMailer(credentials, y.GetService<IEmailComposer>()))
.WithCompiler<ScribanCompiler>()
.WithTemplateProvider(x => new AppDirectoryTemplateProvider("Templates", ".sbnhtml"))
.WithResolver<ViewModelTemplateResolver>()
.WithDefaultComposer();
});
```

## Usage

The power of this project is to create a dynamic mail body as you can populate any template with any type of data. This is when the compilers, providers and resolvers come in. They can be produced using the `MailBodyBuilder` class, which orchestrates the process of retrieving and populating the template. It is ultimately up to the instance of the `IMailer` to actually send the e-mail.
The power of this project is to create a dynamic mail body as you can populate any template with any type of data. This is when the compilers, providers and resolvers come in. They can be produced using the implementation of `IEmailCompiler`, which orchestrates the process of retrieving and populating the template. It is ultimately up to the instance of the `IMailer` to actually send the email.

``` csharp
public async Task SendConfirmationMail(string customerMail, string customerName)
{
EmailComposer<TestMailModel> composer = new EmailComposer<TestMailModel>();
EmailRequest<TestMailModel> request = composer
.SetModel(new TestMailModel { Email = customerMail, Name = customerMail })
EmailComposer composer = new(
new ScribanCompiler(),
new AppDirectoryTemplateProvider("Templates", ".sbnhtml"),
new ViewModelTemplateResolver());

EmailRequest request = await composer
.SetSubject("Hello world")
.SetFrom("info@facteur.com")
.SetTo("guy.gadbois@facteur.com")
.SetCc("jacques.clouseau@facteur.com")
.SetBcc("charles.dreyfus@facteur.com")
.Build();

IMailBodyBuilder builder = new MailBodyBuilder(
new ScribanCompiler(),
new AppDirectoryTemplateProvider("Templates", ".sbnhtml"),
new ViewModelTemplateResolver());

EmailRequest populatedRequest = await builder.BuildAsync(request);
.BuildAsync(new TestMailModel { Email = customerMail, Name = customerMail });

SmtpCredentials credentials = new("smtp.gmail.com", "587", "false", "true", "myuser@gmail.com", "mypassword");
IMailer mailer = new SmtpMailer(credentials);
await mailer.SendMailAsync(populatedRequest);
await mailer.SendMailAsync(request);
}
```

If you use DI, you can just use `IMailer` and use the overload that exposes the composer:

``` csharp
public async Task SendConfirmationMail(string customerMail, string customerName)
{
await mailer.SendMailAsync(x => x
.SetSubject("Hello world")
.SetFrom("info@facteur.com")
.SetTo("guy.gadbois@facteur.com")
.SetCc("jacques.clouseau@facteur.com")
.SetBcc("charles.dreyfus@facteur.com")
.BuildAsync(new TestMailModel { Email = customerMail, Name = customerMail }));
}
```

Expand All @@ -130,17 +152,12 @@ public class TestMailModel

The resolver is responsible for locating the right file name. In this example, the `ViewModelTemplateResolver` is used. This class essentially strips the 'MailModel' or 'ViewModel' of the name of the mail request's model. After that, the provider (`AppDirectoryTemplateProvider`) will make the system to look for file in the application's `Templates` directory with the .sbnhtml file and with the name 'Test' (from Test~~MailModel~~).

The `IMailBodyBuilder` brings everything together and generates a populated mail body. Then it's up to the `ÌMailer` to merely send the mail.
The `IEmailComposer` brings everything together and generates a populated mail body. Then it's up to the `ÌMailer` to merely send the mail.

With .NET's dependency injection, hooking up the mailer is as simple as adding one line in the Startup class:
## Contributing

```csharp
services.AddMailer<SmtpMailer, ScribanCompiler, AppDirectoryTemplateProvider, ViewModelTemplateResolver>(
mailerFactory: x => new SmtpMailer(credentials),
templateProviderFactory: x => new AppDirectoryTemplateProvider("Templates", ".sbnhtml")
);
```
Pull requests are welcome. Please check out the contribution and code of conduct guidelines.

## Contributing
## License

Pull requests are welcome. Please check out the contribution and code of conduct guidelines.
<img src="https://img.shields.io/badge/License-MIT-brightgreen.svg?style=flat-square" />
Loading

0 comments on commit a7dc0b5

Please sign in to comment.