Skip to content

Commit 723bad5

Browse files
author
Eric Boumendil
committed
Bug fix and added void filter
1 parent 0b2181a commit 723bad5

File tree

9 files changed

+83
-11
lines changed

9 files changed

+83
-11
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Internally, [MailKit](https://github.com/jstedfast/MailKit) is used for SMTP for
1414
- Replace subject of some messages with LLM completion based on message body (OpenAI-compatible API like [llama.cpp](https://github.com/ggerganov/llama.cpp/tree/master)).
1515
- Filter by destination address (if enabled, SMTP will reject unknown recipients).
1616
- Filter by message size (SMTP will reject message reaching a threshold).
17+
- Void filter (trash messages based on regular expressions).
1718
- Catch up on next program startup (messages not send yet at shutdown are sent on startup).
1819
- Unsecure Basic authentication (user/password without TLS) and anonymous authentication.
1920

examples/configuration/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,23 @@ The previous example will replace subject of messages that contain "notification
121121

122122
The prompt sent to LLM will contain default user instructions followed by message body. You can customize the user prompt with a parameter *UserPrompt* inside a rule (it must contain a placeholder `%1` for replacement with message body). You also can customize system prompt with a parameter *SystemPrompt* in section *LlmEnrichment* (no variable placeholder required for the system prompt), or directly in primary configuration of *LlmClient* (see related section in this page).
123123
Unless for complex configuration, custom system prompt should be in *LlmClient* (shared for any usage of the LLM client).
124+
125+
## Trash messages (void filter)
126+
127+
If an SMTP client repeatedly sends notifications you're not interested in, it may be useful to filter them out from SmtpLocalRelay this way:
128+
129+
```js
130+
{
131+
"SmtpForwarder": {
132+
"Void": {
133+
"Matchers": [
134+
{
135+
"RegexOnField": "Subject, Body",
136+
"Regex": "Arpwatch Notification : flip flop.+?old ethernet address: ab:cd:ef",
137+
}
138+
]
139+
}
140+
}
141+
}
142+
```
143+

examples/docker/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: '3.1'
22
services:
33
localsmtprelay:
4-
image: eric1901/localsmtprelay:1.2.0
4+
image: eric1901/localsmtprelay:1.2.1
55
ports:
66
- "25:25/tcp"
77
environment:

examples/kubernetes/localsmtprelay-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ spec:
2727
containers:
2828
- name: localsmtprelay
2929
imagePullPolicy: IfNotPresent
30-
image: eric1901/localsmtprelay:1.2.0
30+
image: eric1901/localsmtprelay:1.2.1
3131
ports:
3232
- containerPort: 25
3333
volumeMounts:

src/LocalSmtpRelay/Components/AlertManager/AlertManagerForwarder.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using LocalSmtpRelay.Model;
1+
using LocalSmtpRelay.Helpers;
2+
using LocalSmtpRelay.Model;
23
using Microsoft.Extensions.Logging;
34
using Microsoft.Extensions.Options;
45
using MimeKit;
@@ -17,8 +18,6 @@ public sealed class AlertManagerForwarder(IOptions<AlertManagerForwarderOptions>
1718
LlmAlertSummarizer llm,
1819
ILogger<AlertManagerForwarder> logger)
1920
{
20-
private static readonly TimeSpan RegexTimeout = TimeSpan.FromSeconds(10);
21-
2221
private readonly bool _disable = options.Value.Disable;
2322
private readonly MessageRule[] _rules = options.Value.MessageRules ?? [];
2423
private readonly Dictionary<string, int> defaultAlertNumberBySubject = new(StringComparer.OrdinalIgnoreCase);
@@ -98,7 +97,7 @@ public async Task<bool> TrySendAlert(MimeMessage message, CancellationToken canc
9897
input += $"\r\n{textBody}";
9998

10099
if (rule.ResolutionRegex != null &&
101-
Regex.IsMatch(input, rule.ResolutionRegex, RegexOptions.None, RegexTimeout))
100+
RegexHelper.IsMatch(input, rule.ResolutionRegex))
102101
{
103102
if (alert is null)
104103
alert = new Alert();
@@ -112,7 +111,7 @@ public async Task<bool> TrySendAlert(MimeMessage message, CancellationToken canc
112111
if (!rule.EvaluateOtherRules)
113112
break;
114113
}
115-
else if (Regex.IsMatch(input, rule.AlertRegex, RegexOptions.None, RegexTimeout))
114+
else if (RegexHelper.IsMatch(input, rule.AlertRegex))
116115
{
117116
if (alert is null)
118117
alert = new Alert();

src/LocalSmtpRelay/Components/SmtpForwarder.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using LocalSmtpRelay.Components.Llm;
2323
using System.Text.RegularExpressions;
2424
using System.Text.Json;
25+
using LocalSmtpRelay.Helpers;
2526

2627
namespace LocalSmtpRelay.Components
2728
{
@@ -140,6 +141,13 @@ private async Task ProcessSend(FileInfo file, CancellationToken cancellationToke
140141
{
141142
using MimeMessage message = await MimeMessage.LoadAsync(file.FullName, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
142143
TryFillTextBodyFromHtml(message);
144+
if (ShouldSendToVoid(message))
145+
{
146+
if (!Utility.TryDeleteFile(file))
147+
_logger.LogWarning("Failed to delete: {File}", file);
148+
return;
149+
}
150+
143151
if (await _alertManagerForwarder.TrySendAlert(message, cancellationToken).ConfigureAwait(continueOnCapturedContext: false))
144152
{
145153
_logger.LogInformation("SmtpForwarder forwarded message to Alertmanager: {Subject}", message.Subject);
@@ -215,6 +223,20 @@ private async Task ProcessSend(FileInfo file, CancellationToken cancellationToke
215223
}
216224
}
217225

226+
private bool ShouldSendToVoid(MimeMessage message)
227+
{
228+
return Array.Exists(_options.CurrentValue.Void.Matchers, m =>
229+
{
230+
string regexInput = string.Empty;
231+
if (m.RegexOnField.HasFlag(Model.MessageField.Subject))
232+
regexInput = message.Subject;
233+
if (m.RegexOnField.HasFlag(Model.MessageField.Body))
234+
regexInput += $"\r\n{message.TextBody}";
235+
236+
return RegexHelper.IsMatch(regexInput, m.Regex);
237+
});
238+
}
239+
218240
/// <summary>
219241
/// If a rule matches this message, LLM is applied to the text body
220242
/// to replace the subject.
@@ -235,9 +257,9 @@ private async Task TryReplaceSubjectWithLlm(MimeMessage message, CancellationTok
235257
if (r.RegexOnField.HasFlag(Model.MessageField.Subject))
236258
regexInput = message.Subject;
237259
if (r.RegexOnField.HasFlag(Model.MessageField.Body))
238-
regexInput += $"\r\ntextBody";
260+
regexInput += $"\r\n{textBody}";
239261

240-
return Regex.IsMatch(regexInput, r.Regex, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(10));
262+
return RegexHelper.IsMatch(regexInput, r.Regex);
241263
});
242264

243265
if (rule != null)

src/LocalSmtpRelay/Components/SmtpForwarderOptions.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public sealed class SmtpForwarderOptions
2424

2525
public Llm LlmEnrichment { get; } = new();
2626

27+
public VoidFilter Void { get; } = new();
28+
2729
public class AuthenticationParameters
2830
{
2931
public string Username { get; set; } = default!;
@@ -50,7 +52,22 @@ public sealed class Llm
5052
public string? UserPrompt { get; set; }
5153

5254

53-
public LlmRule[] Rules { get; } = [];
55+
public LlmRule[] Rules { get; set; } = [];
56+
}
57+
58+
public sealed class VoidFilter
59+
{
60+
public VoidMatcherRule[] Matchers { get; set; } = [];
61+
}
62+
63+
public sealed class VoidMatcherRule
64+
{
65+
/// <summary>
66+
/// If regex matches, message will be ignored.
67+
/// </summary>
68+
public string Regex { get; set; } = default!;
69+
70+
public MessageField RegexOnField { get; set; }
5471
}
5572

5673
public sealed class LlmRule
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Text.RegularExpressions;
3+
4+
namespace LocalSmtpRelay.Helpers
5+
{
6+
internal static class RegexHelper
7+
{
8+
private static readonly TimeSpan RegexTimeout = TimeSpan.FromSeconds(10);
9+
10+
public static bool IsMatch(string input, string regex)
11+
=> Regex.IsMatch(input, regex, RegexOptions.IgnoreCase | RegexOptions.Singleline, RegexTimeout);
12+
}
13+
}

src/LocalSmtpRelay/LocalSmtpRelay.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<PropertyGroup>
1414
<DockerfileRunArguments>-p 25:25</DockerfileRunArguments>
15-
<Version>1.2.0</Version>
15+
<Version>1.2.1</Version>
1616
<InvariantGlobalization>true</InvariantGlobalization>
1717
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
1818
</PropertyGroup>

0 commit comments

Comments
 (0)