Skip to content

Commit

Permalink
Mailer-fixes (#402)
Browse files Browse the repository at this point in the history
Mostly mailer fixes + improvements.

- Issue where globalFrom was taking precedence over explicitly defined from email address in code
- Adds ability to assign "sender" field (breaking change to custom mailer)
- Added globalFrom documentation
- Sender documentation
  • Loading branch information
jamesmh authored Sep 20, 2024
1 parent 6eb2c27 commit 746d832
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 53 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,40 @@ jobs:
run: dotnet test ./Src/UnitTests/CoravelUnitTests/CoravelUnitTests.csproj
- name: Integration Tests
run: dotnet test ./Src/IntegrationTests/Tests/Tests.csproj
build_and_tests_on_dotnet_7:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Restore dependencies
run: dotnet restore ./Src/All.sln
- name: Build
run: dotnet build ./Src/All.sln
- name: Mailer Tests
run: dotnet test ./Src/UnitTests/MailerUnitTests/MailerUnitTests.csproj
- name: Unit Tests
run: dotnet test ./Src/UnitTests/CoravelUnitTests/CoravelUnitTests.csproj
- name: Integration Tests
run: dotnet test ./Src/IntegrationTests/Tests/Tests.csproj
build_and_tests_on_dotnet_8:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore ./Src/All.sln
- name: Build
run: dotnet build ./Src/All.sln
- name: Mailer Tests
run: dotnet test ./Src/UnitTests/MailerUnitTests/MailerUnitTests.csproj
- name: Unit Tests
run: dotnet test ./Src/UnitTests/CoravelUnitTests/CoravelUnitTests.csproj
- name: Integration Tests
run: dotnet test ./Src/IntegrationTests/Tests/Tests.csproj

6 changes: 3 additions & 3 deletions Demo/Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<AddRazorSupportForMvc>True</AddRazorSupportForMvc>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.0" />
<!-- <PackageReference Include="Coravel" Version="3.3.0" /> -->
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Src\Coravel\Coravel.csproj" />
<ProjectReference Include="..\Src\Coravel.Mailer\Coravel.Mailer.csproj" />
<ProjectReference Include="..\Src\Coravel.Cache.Database\Coravel.Cache.SqlServer\Coravel.Cache.SqlServer.csproj" />
<ProjectReference Include="..\Src\Coravel.Cache.Database\Coravel.Cache.PostgreSQL\Coravel.Cache.PostgreSQL.csproj" />

<ProjectReference Include="..\Src\Coravel.Cache.Database\Coravel.Cache.PostgreSQL\Coravel.Cache.PostgreSQL.csproj" />
</ItemGroup>

</Project>
19 changes: 10 additions & 9 deletions Demo/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public void ConfigureServices(IServiceCollection services)
options.MinimumSameSitePolicy = SameSiteMode.None;
});

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMvc(options => { options.EnableEndpointRouting = false; }).AddRazorRuntimeCompilation();
services.AddControllersWithViews();

// Coravel Scheduling
services.AddScheduler();
Expand Down Expand Up @@ -68,19 +69,19 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
// app.UseHsts();
}

app.UseHttpsRedirection();
// app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();

// app.UseMvc(routes =>
// {
// routes.MapRoute(
// name: "default",
// template: "{controller=Home}/{action=Index}/{id?}");
// });
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});

IEventRegistration registration = app.ApplicationServices.ConfigureEvents();

Expand Down
65 changes: 43 additions & 22 deletions DocsV2/docs/Mailing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ async Task SendMailCustomAsync(
MailRecipient replyTo,
IEnumerable<MailRecipient> cc,
IEnumerable<MailRecipient> bcc,
IEnumerable<Attachment> attachments = null
IEnumerable<Attachment> attachments = null,
MailRecipient sender = null
)
{
// Custom logic for sending an email.
Expand All @@ -111,6 +112,10 @@ async Task SendMailCustomAsync(
services.AddCustomMailer(this.Configuration, SendMailCustomAsync);
```

:::warn
Breaking changes to this method signature are more likely than other as this is the signature that the Mailer's internals use. If a new version of the Mailer causes your code to stop compiling sucessfully, it's probably this signature that needs to be updated. Luckliy, it's usually a quick change in 1 spot.
:::

### Built-In View Templates

Coravel's mailer comes with some pre-built e-mail friendly razor templates! This means you don't have to worry about
Expand All @@ -134,7 +139,7 @@ What about static content like the mail footer and logo? Coravel's got you cover

In your `appsettings.json`, you may add the following global values that will populate when using Coravel's built-in templates:

```
```json
"Coravel": {
"Mail": {
/* Your app's logo that will be shown at the top of your e-mails. */
Expand Down Expand Up @@ -195,35 +200,53 @@ You can then call various methods like `To` and `From` to configure the recipien

### From

To specify who the sender of the email is, use the `From()` method:
To specify who the email is from, use the `From()` method:

`From("test@test.com")`
```csharp
From("test@test.com")
```

You may also supply an instance of `Coravel.Mailer.Mail.MailRecipient` to include the address and sender name:

`From(new MailRecipient(email, name))`
```csharp
From(new MailRecipient(email, name))
```

### Send To Recipient
You can set a global from address by setting it in `appsettings.json`:

Using the `To()` method, you can supply the recipient's e-mail address and name.

#### Address
```json
"Coravel": {
"Mail": {
"From":{
"Address": "global@from.com",
"Name": "My Company"
}
}
}
```

Using an e-mail address in a `string`:
### To

`To("test@test.com")`
Using the `To()` method, you can supply the recipient's e-mail address and name.

#### Multiple Addresses
Or, using an e-mail address in a `string`:

You can pass`IEnumerable<string>` to the `To()` method.
```csharp
To("test@test.com")
```

#### MailRecipient
You can also pass:
- `To(IEnumerable<string>)`
- `To(MailRecipient)`
- `To(IEnumerable<MailRecipient>)`

Pass an instance of `MailRecipient` to the `To()` method.
### Sender

#### Multiple MailRecipients
To specify the sender of the email (different from the `From` address), use the `Sender()` method:

Pass an `IEnumerable<MailRecipient>` to the `To()` method.
```csharp
Sender("test@test.com")
```

#### Attachments

Expand Down Expand Up @@ -261,18 +284,16 @@ Further methods, which all accept either `IEnumerable<string>` or `IEnumerable<M

##### .NET Core 3.1+

In .NET Core 3.1 there were some breaking changes to the way razor views are handled.
For a standard .NET 6+ web project, this should work out-of-the-box. If using a shared library, the following applies.

Which ever project(s) you have razor views inside, you'll need to make sure .NET compiles them at build time.
In .NET Core 3.1 there were some breaking changes to the way razor views are handled.

Here's what you'll need to change within your `.csproj` file to enable this:
If you have a shared library with razor views inside, you'll need to make sure .NET compiles them at build time by adding the following to your `.csproj`:

```xml
<Project Sdk="Microsoft.NET.Sdk.Razor"> 👈 Make sure it's this SDK.

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AddRazorSupportForMvc>True</AddRazorSupportForMvc> 👈 Add this too.
</PropertyGroup>
```
Expand Down
1 change: 0 additions & 1 deletion Samples/EFCoreSample/test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

<ItemGroup>
<PackageReference Include="coravel" Version="2.4.1" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.3" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

<ItemGroup>
<PackageReference Include="Coravel" Version="2.3.1" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
</ItemGroup>

Expand Down
7 changes: 7 additions & 0 deletions Src/Coravel.Mailer/Coravel.Mailer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<PackageReadmeFile>./readme.md</PackageReadmeFile>
<PackageIcon>./logo.png</PackageIcon>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MailKit" Version="2.5.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.0" />
</ItemGroup>

<ItemGroup>
<None Include="readme.md" Pack="true" PackagePath="\" />
<None Include="logo.png" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Src/Coravel.Mailer/Mail/Interfaces/IMailer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public interface IMailer
{
Task<string> RenderAsync<T>(Mailable<T> mailable);
Task SendAsync<T>(Mailable<T> mailable);
Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments = null);
Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments = null, MailRecipient sender = null);
}
}
17 changes: 16 additions & 1 deletion Src/Coravel.Mailer/Mail/Mailable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public class Mailable<T>
/// </summary>
private MailRecipient _from;

/// <summary>
/// The email sender.
/// </summary>
private MailRecipient _sender;

/// <summary>
/// Recipients of the message.
/// </summary>
Expand Down Expand Up @@ -73,6 +78,15 @@ public Mailable<T> From(MailRecipient recipient)
public Mailable<T> From(string email) =>
this.From(new MailRecipient(email));

public Mailable<T> Sender(MailRecipient recipient)
{
this._sender = recipient;
return this;
}

public Mailable<T> Sender(string email) =>
this.Sender(new MailRecipient(email));

public Mailable<T> To(IEnumerable<MailRecipient> recipients)
{
this._to = recipients;
Expand Down Expand Up @@ -175,7 +189,8 @@ await mailer.SendAsync(
this._replyTo,
this._cc,
this._bcc,
this._attachments
this._attachments,
sender: this._sender
).ConfigureAwait(false);
}

Expand Down
6 changes: 4 additions & 2 deletions Src/Coravel.Mailer/Mail/Mailers/AssertMailer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class Data
public string subject { get; set; }
public IEnumerable<MailRecipient> to { get; set; }
public MailRecipient from { get; set; }
public MailRecipient sender { get; set; }
public MailRecipient replyTo { get; set; }
public IEnumerable<MailRecipient> cc { get; set; }
public IEnumerable<MailRecipient> bcc { get; set; }
Expand All @@ -26,7 +27,7 @@ public AssertMailer(Action<Data> assertAction)
this._assertAction = assertAction;
}

public Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments)
public Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments, MailRecipient sender = null)
{
this._assertAction(new Data
{
Expand All @@ -37,7 +38,8 @@ public Task SendAsync(string message, string subject, IEnumerable<MailRecipient>
replyTo = replyTo,
cc = cc,
bcc = bcc,
attachments = attachments
attachments = attachments,
sender = sender
});
return Task.CompletedTask;
}
Expand Down
6 changes: 3 additions & 3 deletions Src/Coravel.Mailer/Mail/Mailers/CustomMailer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Coravel.Mailer.Mail.Mailers
{
public class CustomMailer : IMailer
{
public delegate Task SendAsyncFunc(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments = null);
public delegate Task SendAsyncFunc(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments = null, MailRecipient sender = null);
private RazorRenderer _renderer;
private SendAsyncFunc _sendAsyncFunc;
private MailRecipient _globalFrom;
Expand All @@ -25,10 +25,10 @@ public Task<string> RenderAsync<T>(Mailable<T> mailable) =>
public async Task SendAsync<T>(Mailable<T> mailable) =>
await mailable.SendAsync(this._renderer, this);

public async Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments)
public async Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments, MailRecipient sender = null)
{
await this._sendAsyncFunc(
message, subject, to, this._globalFrom ?? from, replyTo, cc, bcc, attachments
message, subject, to, from ?? this._globalFrom, replyTo, cc, bcc, attachments, sender: sender
);
}
}
Expand Down
5 changes: 3 additions & 2 deletions Src/Coravel.Mailer/Mail/Mailers/FileLogMailer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public async Task<string> RenderAsync<T>(Mailable<T> mailable)
return await mailable.RenderAsync(this._renderer, this);
}

public async Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments = null)
public async Task SendAsync(string message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment> attachments = null, MailRecipient sender = null)
{
from = this._globalFrom ?? from;
from = from ?? this._globalFrom;

using (var writer = File.CreateText(FilePath))
{
Expand All @@ -38,6 +38,7 @@ await writer.WriteAsync($@"
Subject: {subject}
To: {CommaSeparated(to)}
From: {DisplayAddress(from)}
Sender: { (sender is null ? "N/A" : DisplayAddress(sender)) }
ReplyTo: {DisplayAddress(replyTo)}
Cc: {CommaSeparated(cc)}
Bcc: {CommaSeparated(bcc)}
Expand Down
Loading

0 comments on commit 746d832

Please sign in to comment.