////
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
////

[#smtpappender]
= SmtpAppender

The `SmtpAppender` sends log events via email using the Simple Mail Transfer Protocol (SMTP).
This appender is useful for sending email notifications when certain events occur, such as errors or critical failures in your application.

There are two implementations to choose from:

[cols="Type,Assembly,SMTP client"]
|===
|Type |Assembly |SMTP client

|`log4net.Ext.Mail.Appender.SmtpAppender` (recommended)
|`log4net.Ext.Mail`
|https://github.com/jstedfast/MailKit[MailKit]

|`log4net.Appender.SmtpAppender` (deprecated)
|`log4net`
|`System.Net.Mail.SmtpClient`
|===

[IMPORTANT]
====
The built-in `log4net.Appender.SmtpAppender` is *no longer recommended*.

It sends mail through https://learn.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient#remarks[System.Net.Mail.SmtpClient], which Microsoft no longer recommends for new development because it does not support many modern protocols.
In practice this shows up as connection failures against modern mail servers, most often around SSL/TLS negotiation.

Use the xref:#mailkit-smtpappender[MailKit based `SmtpAppender`] instead.
It offers the same configuration options, so migrating usually means changing nothing but the `type` attribute.
====

[#mailkit-smtpappender]
== MailKit based SmtpAppender (recommended)

This appender lives in the separate `log4net.Ext.Mail` package, so that log4net itself does not take on a mail dependency.
Add it to your project:

[source,shell]
----
dotnet add package log4net.Ext.Mail
----

Because the appender is not part of the `log4net` assembly, the `type` attribute must be assembly-qualified:

[source,xml]
----
type="log4net.Ext.Mail.Appender.SmtpAppender, log4net.Ext.Mail"
----

The following example shows how to configure the `SmtpAppender` to deliver log events via SMTP email.
The `To`, `From`, `Subject` and `SmtpHost` are required parameters.
This example shows how to deliver only significant events.

A LevelEvaluator is specified with a threshold of WARN.
This means that an email will be sent for each WARN or higher level message that is logged.
Each email will also contain up to 512 (BufferSize) previous messages of any level to provide context.

Messages not sent will be discarded.

[source,xml]
----
<appender name="SmtpAppender" type="log4net.Ext.Mail.Appender.SmtpAppender, log4net.Ext.Mail">
  <to value="to@example.com" />
  <from value="from@example.com" />
  <subject value="test logging message" />
  <smtpHost value="smtp.example.com" />
  <bufferSize value="512" />
  <lossy value="true" />
  <evaluator type="log4net.Core.LevelEvaluator">
    <threshold value="WARN"/>
  </evaluator>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%newline%date [%thread] %-5level %logger - %message%newline%newline%newline" />
  </layout>
</appender>
----

This example shows how to configure the `SmtpAppender` to deliver all messages in emails with 512 `bufferSize` messages per email.

[source,xml]
----
<appender name="SmtpAppender" type="log4net.Ext.Mail.Appender.SmtpAppender, log4net.Ext.Mail">
  <to value="to@example.com" />
  <from value="from@example.com" />
  <subject value="test logging message" />
  <smtpHost value="smtp.example.com" />
  <bufferSize value="512" />
  <lossy value="false" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%newline%date [%thread] %-5level %logger - %message%newline%newline%newline" />
  </layout>
</appender>
----

This example shows a more verbose formatting layout for the mail messages.

[source,xml]
----
<appender name="SmtpAppender" type="log4net.Ext.Mail.Appender.SmtpAppender, log4net.Ext.Mail">
  <to value="to@example.com" />
  <from value="from@example.com" />
  <subject value="test logging message" />
  <smtpHost value="smtp.example.com" />
  <bufferSize value="512" />
  <lossy value="false" />
  <evaluator type="log4net.Core.LevelEvaluator,log4net">
    <threshold value="WARN" />
  </evaluator>
  <layout type="log4net.Layout.PatternLayout,log4net">
    <conversionPattern value="%property{log4net:HostName} :: %level :: %message %newlineLogger: %logger%newlineThread: %thread%newlineDate: %date%newline%newline" />
  </layout>
</appender>
----

This example authenticates against a mail server that requires an encrypted connection on the submission port.

[source,xml]
----
<appender name="SmtpAppender" type="log4net.Ext.Mail.Appender.SmtpAppender, log4net.Ext.Mail">
  <to value="ops@example.com,oncall@example.com" />
  <cc value="team@example.com" />
  <from value="log4net@example.com" />
  <replyTo value="noreply@example.com" />
  <subject value="Errors from the payment service" />
  <smtpHost value="smtp.example.com" />
  <port value="587" />
  <enableSsl value="true" />
  <authentication value="Basic" />
  <username value="log4net@example.com" />
  <password value="secret" />
  <priority value="High" />
  <bufferSize value="512" />
  <lossy value="true" />
  <evaluator type="log4net.Core.LevelEvaluator">
    <threshold value="ERROR"/>
  </evaluator>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%newline%date [%thread] %-5level %logger - %message%newline" />
  </layout>
</appender>
----

[#mailkit-smtpappender-options]
=== Options

[cols="Option,Description"]
|===
|Option |Description

|`to`
|*Required.* Comma-delimited list of recipient email addresses.

|`from`
|*Required.* The sender's email address.

|`subject`
|*Required.* The subject line of the email.

|`smtpHost`
|*Required.* The name or address of the SMTP relay server.

|`cc`
|Comma-delimited list of addresses to carbon copy.

|`bcc`
|Comma-delimited list of addresses to blind carbon copy.

|`replyTo`
|The reply-to address.

|`port`
|The port the SMTP server listens on. Defaults to `25`.

|`enableSsl`
|Whether to require transport security. Defaults to `false`.
Shorthand for `transportSecurity`: `true` selects `Required`, `false` selects `None`.

|`transportSecurity`
|How the connection is secured. One of `None` (default), `Required`, `ImplicitTls`, `StartTls` or `StartTlsWhenAvailable`.
See xref:#mailkit-smtpappender-transport-security[].

|`authentication`
|One of `None` (default), `Basic` or `Ntlm`. `Basic` and `Ntlm` both require `username` and `password`.

|`username`
|The user name to authenticate with. Ignored when `authentication` is `None`.

|`password`
|The password to authenticate with. Ignored when `authentication` is `None`.

|`priority`
|One of `Low`, `Normal` (default) or `High`, mapped onto the MIME `Priority` header.

|`subjectEncoding`
|The encoding of the subject line, for example `utf-8`. Defaults to `utf-8`.

|`bodyEncoding`
|The encoding of the message body, for example `utf-8`. Defaults to `utf-8`.

|`bufferSize`
|How many log events to buffer into one email. See xref:manual/configuration/appenders.adoc[].

|`lossy`
|Whether buffered events may be discarded rather than sent.

|`evaluator`
|An `ITriggeringEventEvaluator` deciding which events trigger a send.
|===

`to`, `cc` and `bcc` also accept semicolons as separators, and quoted display names such as `"Doe, John" <john@example.com>`.

[#mailkit-smtpappender-transport-security]
=== Transport security

`enableSsl` covers the usual cases and behaves as it does in the legacy appender: `true` requires
transport security, so connecting fails when the server does not offer it rather than continuing
unencrypted.

`transportSecurity` is the same setting expressed precisely, for servers that need something else.
The two properties cannot disagree: whichever is assigned last wins.

[cols="Value,Description"]
|===
|Value |Description

|`None`
|The connection is not encrypted. Equivalent to `enableSsl` set to `false`, and the default.

|`Required`
|Transport security is required and the mechanism follows the port: implicit TLS on port 465,
`STARTTLS` on every other port. Equivalent to `enableSsl` set to `true`.

|`ImplicitTls`
|The session is encrypted before the SMTP greeting, whatever the port.
Use this for a server expecting implicit TLS on a port other than 465, which `Required` would try
to negotiate with `STARTTLS` instead.

|`StartTls`
|`STARTTLS` is required, whatever the port.

|`StartTlsWhenAvailable`
|`STARTTLS` is used when the server advertises it, and the connection continues unencrypted when it
does not.
|===

[WARNING]
====
`StartTlsWhenAvailable` is opportunistic.
An attacker able to modify the traffic can remove the server's `STARTTLS` advertisement, and the
session then proceeds in plaintext, exposing the credentials sent by `authentication` and the log
content itself.
Only choose it for a network where that is acceptable, and prefer `Required`.
====

[#mailkit-smtpappender-differences]
=== Differences from the legacy appender

The options above are named exactly as in the legacy appender, but a few behave differently:

* `smtpHost` is *required*. MailKit has no notion of a machine-wide default SMTP server, so there is nothing to fall back on when the option is omitted.
* `authentication` set to `Ntlm` requires `username` and `password`.
MailKit cannot reuse the Windows logon session of the current thread or process, which the legacy appender did.
* Semicolon-delimited recipient lists in `to`, `cc` and `bcc` are parsed correctly.
* `transportSecurity` has no counterpart in the legacy appender, which offers only `enableSsl`.

`enableSsl` keeps its meaning, so a migrated configuration secures the connection exactly as before.
If the legacy appender reached your server with `enableSsl` set to `true`, so does this one.
The new `transportSecurity` option is only needed for a server that the legacy appender could not
reach either, such as one expecting implicit TLS on a port other than 465.

[#legacy-smtpappender]
== Built-in SmtpAppender (deprecated)

[NOTE]
====
This appender is still shipped and still works, but it is marked `[Obsolete]`, so referencing
`log4net.Appender.SmtpAppender` from code produces a compiler warning.
Configuring it from XML keeps working without any warning.
See the note at the xref:#smtpappender[top of this page].
====

The built-in appender is configured with the same options, except for the differences listed in xref:#mailkit-smtpappender-differences[].
It needs no assembly-qualified type name, because it is part of the `log4net` assembly.

[source,xml]
----
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
  <to value="to@example.com" />
  <from value="from@example.com" />
  <subject value="test logging message" />
  <smtpHost value="smtp.example.com" />
  <bufferSize value="512" />
  <lossy value="true" />
  <evaluator type="log4net.Core.LevelEvaluator">
    <threshold value="WARN"/>
  </evaluator>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%newline%date [%thread] %-5level %logger - %message%newline%newline%newline" />
  </layout>
</appender>
----

If you cannot take on the MailKit dependency, xref:manual/configuration/appenders/smtppickupdirappender.adoc[] is an alternative that avoids an SMTP client altogether by writing the emails to a pickup directory.