Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Src/SmtpServer/ISmtpServerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,12 @@ public interface ISmtpServerOptions
/// The size of the buffer that is read from each call to the underlying network client.
/// </summary>
int NetworkBufferSize { get; }

/// <summary>
/// Gets the custom SMTP greeting message that the server sends immediately after a client connects,
/// typically as the initial "220" response. The message can be dynamically generated based on the session context.
/// If not set, a default greeting will be used (e.g., "220 mail.example.com ESMTP ready").
/// </summary>
Func<ISessionContext, string> CustomSmtpGreeting { get; }
}
}
25 changes: 25 additions & 0 deletions Src/SmtpServer/SmtpServerOptionsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public ISmtpServerOptions Build()
MaxAuthenticationAttempts = 3,
NetworkBufferSize = 128,
CommandWaitTimeout = TimeSpan.FromMinutes(5),
CustomSmtpGreeting = null,
};

_setters.ForEach(setter => setter(serverOptions));
Expand Down Expand Up @@ -157,6 +158,23 @@ public SmtpServerOptionsBuilder CommandWaitTimeout(TimeSpan value)
return this;
}

/// <summary>
/// Sets the custom SMTP greeting message sent to the client upon connection,
/// typically returned as the initial "220" response.
/// </summary>
/// <param name="smtpGreetingFunc">
/// A delegate that returns the greeting message to send to the client,
/// based on the <see cref="ISessionContext"/> (e.g., client IP, TLS state).
/// Example: <c>ctx => $"220 {sessionContext.ServerOptions.ServerName} ESMTP ready"</c>
/// </param>
/// <returns>An OptionsBuilder to continue building on.</returns>
public SmtpServerOptionsBuilder CustomGreetingMessage(Func<ISessionContext, string> smtpGreetingFunc)
{
_setters.Add(options => options.CustomSmtpGreeting = smtpGreetingFunc);

return this;
}

#region SmtpServerOptions

class SmtpServerOptions : ISmtpServerOptions
Expand Down Expand Up @@ -200,6 +218,13 @@ class SmtpServerOptions : ISmtpServerOptions
/// The size of the buffer that is read from each call to the underlying network client.
/// </summary>
public int NetworkBufferSize { get; set; }

/// <summary>
/// Gets or sets the custom greeting message sent by the server in response to the initial SMTP connection.
/// This message is returned after the client connects and before any commands are issued (e.g., "220 mail.example.com v1.0 ESMTP ready").
/// If not set, a default greeting will be used.
/// </summary>
public Func<ISessionContext, string> CustomSmtpGreeting { get; set; }
}

#endregion
Expand Down
27 changes: 17 additions & 10 deletions Src/SmtpServer/SmtpSession.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using SmtpServer.Protocol;
using System.Reflection;
using SmtpServer.ComponentModel;
using SmtpServer.IO;
using System.IO.Pipelines;
using SmtpServer.Protocol;
using SmtpServer.StateMachine;
using SmtpServer.ComponentModel;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace SmtpServer
{
internal sealed class SmtpSession
{
const string BufferKey = "SmtpSession:Buffer";
static readonly Version AssemblyVersion = typeof(SmtpSession).GetTypeInfo().Assembly.GetName().Version;

readonly SmtpStateMachine _stateMachine;
readonly SmtpSessionContext _context;
Expand Down Expand Up @@ -188,9 +189,15 @@ static async Task<bool> ExecuteAsync(SmtpCommand command, SmtpSessionContext con
/// <returns>A task which performs the operation.</returns>
ValueTask<FlushResult> OutputGreetingAsync(CancellationToken cancellationToken)
{
var version = typeof(SmtpSession).GetTypeInfo().Assembly.GetName().Version;

_context.Pipe.Output.WriteLine($"220 {_context.ServerOptions.ServerName} v{version} ESMTP ready");
if (_context.ServerOptions.CustomSmtpGreeting is null)
{
var serverVersion = AssemblyVersion;
_context.Pipe.Output.WriteLine($"220 {_context.ServerOptions.ServerName} v{serverVersion} ESMTP ready");
}
else
{
_context.Pipe.Output.WriteLine(_context.ServerOptions.CustomSmtpGreeting(_context));
}

return _context.Pipe.Output.FlushAsync(cancellationToken);
}
Expand Down
Loading