This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch doc/2.x/extending
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit e5b8161b0860858b6794e4cd998d05e2479a17c1
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Fri Jun 21 17:30:47 2024 +0200

    Revamp `extending.adoc`
---
 src/site/antora/modules/ROOT/pages/manual/api.adoc |   5 +
 .../modules/ROOT/pages/manual/architecture.adoc    |  14 +-
 .../modules/ROOT/pages/manual/extending.adoc       | 294 ++++++++-------------
 .../antora/modules/ROOT/pages/manual/plugins.adoc  |  14 +-
 4 files changed, 133 insertions(+), 194 deletions(-)

diff --git a/src/site/antora/modules/ROOT/pages/manual/api.adoc 
b/src/site/antora/modules/ROOT/pages/manual/api.adoc
index 174c5abcfc..dc8d18df73 100644
--- a/src/site/antora/modules/ROOT/pages/manual/api.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/api.adoc
@@ -85,6 +85,11 @@ include::partial$manual/api-best-practice-use-supplier.adoc[]
 link:../javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`]s are 
the primary entry point for logging.
 In this section we will introduce you to further details about ``Logger``s.
 
+[TIP]
+====
+Refer to xref:manual/architecture.adoc[] to see where ``Logger``s stand in the 
big picture.
+====
+
 [#logger-names]
 === Logger names
 
diff --git a/src/site/antora/modules/ROOT/pages/manual/architecture.adoc 
b/src/site/antora/modules/ROOT/pages/manual/architecture.adoc
index 448b392573..f151b79081 100644
--- a/src/site/antora/modules/ROOT/pages/manual/architecture.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/architecture.adoc
@@ -84,14 +84,15 @@ static method by passing the name of the desired Logger. 
Further
 information on the Logging API can be found in the
 xref:manual/api.adoc[Log4j API].
 
+[#logger-context]
 === LoggerContext
 
-The
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/LoggerContext.html[`LoggerContext`]
-acts as the anchor point for the Logging system. However, it is possible
-to have multiple active LoggerContexts in an application depending on
-the circumstances. More details on the LoggerContext are in the
-xref:manual/logsep.adoc[Log Separation] section.
+The 
link:../javadoc/log4j-api/org/apache/logging/log4j/spi/LoggerContext.html[`LoggerContext`]
 acts as the anchor point for the logging system.
+It is primarily responsible for instantiating <<logger>>s.
+
+In most cases, applications have a single global `LoggerContext`.
+Though in certain cases (e.g., Java EE applications), Log4j can be configured 
to accommodate multiple ``LoggerContext``s.
+Refer to xref:manual/logsep.adoc[] for details.
 
 === Configuration
 
@@ -103,6 +104,7 @@ During reconfiguration, two Configuration objects will 
exist. Once all Loggers
 have been redirected to the new Configuration, the old Configuration
 will be stopped and discarded.
 
+[#logger]
 === Logger
 
 As stated previously, Loggers are created by calling
diff --git a/src/site/antora/modules/ROOT/pages/manual/extending.adoc 
b/src/site/antora/modules/ROOT/pages/manual/extending.adoc
index 00c05df047..679aabb23b 100644
--- a/src/site/antora/modules/ROOT/pages/manual/extending.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/extending.adoc
@@ -14,202 +14,132 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 ////
-= Extending Log4j
 
-Log4j provides numerous ways that it can be manipulated and extended.
-This section includes an overview of the various ways that are directly
-supported by the Log4j 3 implementation.
+= Extending
+
+Log4j provides numerous extension points to adapt it for custom needs.
+Several of such extension points are covered in the page of the associated 
component:
+
+* Log4j API
+** xref:manual/customloglevels.adoc[Extending levels]
+** xref:manual/markers.adoc[Extending markers]
+** xref:manual/messages.adoc#extending[Extending messages]
+** xref:manual/thread-context.adoc#extending[Extending thread context]
+* Log4j Core
+** xref:manual/appenders.adoc#extending[Extending appenders]
+** xref:manual/filters.adoc#extending[Extending filters]
+** xref:manual/layouts.adoc#extending[Extending layouts]
+*** xref:manual/json-template-layout.adoc#extending[Extending JSON Template 
Layout]
+*** xref:manual/pattern-layout.adoc#extending[Extending Pattern Layout]
+** xref:manual/lookups.adoc#extending[Extending lookups]
+
+This section guides you on the rest of the Log4j extension points.
+
+[#mechanisms]
+== Extension mechanisms
+
+Log4j allows extensions primarily using following mechanisms:
+
+[#Custom_Plugins]
+=== Plugins
+
+include::partial$manual/plugin-preliminaries.adoc[]
+
+[#service-loader]
+=== ``ServiceLoader``s
+
+https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/ServiceLoader.html[`ServiceLoader`]
 is a simple service-provider loading facility baked into the Java platform 
itself.
+Log4j uses ``ServiceLoader``s for extending places where
+
+* The service needs to be implementation agnostic.
+As a result, <<Custom_Plugins,the Log4j plugin system>> cannot be used, since 
it is provided by the logging implementation, i.e., Log4j Core.
+For instance, this is why xref:manual/thread-context.adoc#extending[extending 
Thread Context], which is a Log4j API component, works using ``ServiceLoader``s.
+
+* The service needs to be loaded before <<Custom_Plugins,the Log4j plugin 
system>>.
+For instance, this is why <<Provider,extending `Provider`>> works using 
``ServiceLoader``s.
+
+Refer to 
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/ServiceLoader.html[the
 `ServiceLoader` documentation] for details.
+
+[#system-properties]
+=== System properties
+
+Log4j uses system properties to determine the fully-qualified class name 
(FQCN) to load for extending a certain functionality.
+For instance, <<MessageFactory, extending `MessageFactory2`>> works using 
system properties.
+
+[WARNING]
+====
+Loading a class using _only_ its FQCN can result in unexpected behaviour when 
there are multiple class loaders.
+====
+
+[#points]
+== Extension points
+
+In this section we will guide you on certain Log4j extension points that are 
not covered elsewhere.
+
+[#Provider]
+=== `Provider`
+
+link:../javadoc/log4j-api/org/apache/logging/log4j/spi/Provider.html[`Provider`]
 is the anchor contract binding Log4j API to an implementation.
+For instance, it has been implemented by Log4j Core, Log4j-to-JUL bridge, and 
Log4j-to-SLF4J bridge modules.
+
+Under the hood, 
link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`]
 locates a `Provider` implementation using <<service-loader,the `ServiceLoader` 
mechanism>>, and delegates invocations to it.
+Hence, you can extend it by providing a 
`org.apache.logging.log4j.spi.Provider` implementation in the form of a 
`ServiceLoader`.
+
+Having multiple ``Provider``s in the classpath is strongly discouraged.
+Yet when this happens, you can use 
xref:manual/systemproperties.adoc#log4j2.provider[the `log4j2.provider` 
property] to explicitly select one.
 
 [#LoggerContextFactory]
-== LoggerContextFactory
-
-The `LoggerContextFactory` binds the Log4j API to its implementation.
-The Log4j `LogManager` locates a `LoggerContextFactory` by using
-`java.util.ServiceLoader` to locate all instances of
-`org.apache.logging.log4j.spi.Provider`. Each implementation must
-provide a class that extends `org.apache.logging.log4j.spi.Provider` and
-should have a no-arg constructor that delegates to Provider's
-constructor passing the Priority, the API versions it is compatible
-with, and the class that implements
-`org.apache.logging.log4j.spi.LoggerContextFactory`. Log4j will compare
-the current API version and if it is compatible the implementation 
-will be added to the list of providers. The API version in
-`org.apache.logging.log4j.LogManager` is only changed when a feature is
-added to the API that implementations need to be aware of. If more than
-one valid implementation is located the value for the Priority will be
-used to identify the factory with the highest priority. Finally, the
-class that implements
-`org.apache.logging.log4j.spi.LoggerContextFactory` will be instantiated
-and bound to the LogManager. In Log4j 2 this is provided by
-`Log4jContextFactory`.
-
-Applications may change the LoggerContextFactory that will be used by
-
-1.  Create a binding to the logging implementation.
-..  Implement a new 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[`LoggerContextFactory`].
-..  Implement a class that extends
-link:../javadoc/log4j-api/org/apache/logging/log4j/spi/Provider.html[`org.apache.logging.log4j.spi.Provider`]
-with a no-arg constructor that calls super-class's constructor with the
-Priority, the API version(s), `LoggerContextFactory` class, and
-optionally, a
-link:../javadoc/log4j-api/org/apache/logging/log4j/spi/ThreadContextMap.html[`ThreadContextMap`]
-implementation class.
-..  Create a `META-INF/services/org.apache.logging.spi.Provider` file
-that contains the name of the class that implements
-`org.apache.logging.spi.Provider`.
-2.  Setting the system property "log4j2.loggerContextFactory" to the name
-of the `LoggerContextFactory` class to use.
-3.  Setting the property "log4j2.loggerContextFactory" in a properties
-file named "log4j2.LogManager.properties" to the name of the
-LoggerContextFactory class to use. The properties file must be on the
-classpath.
+=== `LoggerContextFactory`
+
+link:../javadoc/log4j-api/org/apache/logging/log4j/spi/LoggerContextFactory.html[`LoggerContextFactory`]
 is the factory class used by Log4j API implementations to create 
xref:manual/architecture.adoc#logger-context[`LoggerContext`]s.
+If you are using Log4j Core, you can provide a custom implementation using 
xref:manual/systemproperties.adoc#log4j2.loggerContextFactory[the 
`log4j2.loggerContextFactory` property].
+Another way to provide a custom `LoggerContextFactory` is to 
<<Provider,provide a custom `Provider`>>.
+But this is generally discouraged, since it requires a more complicated setup 
and is intended mostly to be used by Log4j API implementations.
 
 [#ContextSelector]
-== ContextSelector
-
-ContextSelectors are called by the
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[Log4j
 `LoggerContext` factory]. They perform the actual work of locating or
-creating a LoggerContext, which is the anchor for Loggers and their
-configuration. ContextSelectors are free to implement any mechanism they
-desire to manage LoggerContexts. The default Log4jContextFactory checks
-for the presence of an `Injector` binding for `ContextSelector`.
-If none are defined, the System Property named "Log4jContextSelector" is 
checked.
-If found, the property is expected to contain the name of the Class that 
implements the ContextSelector to be used.
-This class is then used for creating `ContextSelector` instances.
-
-Log4j provides five ContextSelectors:
-
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/BasicContextSelector.html[`BasicContextSelector`]::
-  Uses either a LoggerContext that has been stored in a ThreadLocal or a
-  common LoggerContext.
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html[`ClassLoaderContextSelector`]::
-  Associates LoggerContexts with the ClassLoader that created the caller
-  of the getLogger(...) call. This is the default ContextSelector.
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/JndiContextSelector.html[`JndiContextSelector`]::
-  Locates the LoggerContext by querying JNDI.
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html[`AsyncLoggerContextSelector`]::
-  Creates a LoggerContext that ensures that all loggers are
-  AsyncLoggers.
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/osgi/BundleContextSelector.html[`BundleContextSelector`]::
-  Associates LoggerContexts with the ClassLoader of the bundle that
-  created the caller of the getLogger call. This is enabled by default
-  in OSGi environments.
+=== `ContextSelector`
+
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[`Log4jContextFactory`],
 the Log4j Core implementation of <<LoggerContextFactory>>, delegates the 
actual work to a 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/ContextSelector.html[`ContextSelector`].
+It can be configured using 
xref:manual/systemproperties.adoc#log4j2.contextSelector[the 
`log4j2.contextSelector` property].
 
 [#ConfigurationFactory]
-== ConfigurationFactory
-
-Modifying the way in which logging can be configured is usually one of
-the areas with the most interest. The primary method for doing that is
-by implementing or extending a
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`].
-Log4j provides two ways of adding new ConfigurationFactories. The first
-is by defining the system property named "log4j.configurationFactory" to
-the name of the class that should be searched first for a configuration.
-The second method is by defining the `ConfigurationFactory` as a `Plugin`.
-
-All the ConfigurationFactories are then processed in order. Each factory
-is called on its `getSupportedTypes()` method to determine the file
-extensions it supports. If a configuration file is located with one of
-the specified file extensions then control is passed to that
-`ConfigurationFactory` to load the configuration and create the 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]
 object.
-
-Most `Configuration` extend the 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/AbstractConfiguration.html[`AbstractConfiguration`]
 class. This class expects that the subclass will process the configuration 
file and create
-a hierarchy of `Node` objects. Each `Node` is fairly simple in that it
-consists of the name of the node, the name/value pairs associated with
-the node, The `PluginType` of the node and a List of all of its child
-Nodes. `Configuration` will then be passed the `Node` tree and
-instantiate the configuration objects from that.
-
-[source,java]
-----
-@Namespace("ConfigurationFactory")
-@Plugin("XMLConfigurationFactory")
-@Order(5)
-public class XMLConfigurationFactory extends ConfigurationFactory {
-
-    /**
-     * Valid file extensions for XML files.
-     */
-    public static final String[] SUFFIXES = new String[] {".xml", "*"};
-
-    /**
-     * Returns the Configuration.
-     * @param loggerContext The logger context.
-     * @param source The InputSource.
-     * @return The Configuration.
-     */
-    @Override
-    public Configuration getConfiguration(final LoggerContext loggerContext, 
final ConfigurationSource source) {
-        return new XmlConfiguration(loggerContext, source);
-    }
-
-    /**
-     * Returns the file suffixes for XML files.
-     * @return An array of File extensions.
-     */
-    public String[] getSupportedTypes() {
-        return SUFFIXES;
-    }
-}
-----
+=== `ConfigurationFactory`
+
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`]
 is the factory class used by Log4j Core to create 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]
 instances given a 
xref:manual/architecture.adoc#logger-context[`LoggerContext`] and a 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationSource.html[`ConfigurationSource`].
+
+You can provide a custom `ConfigurationFactory` in the form of a 
<<Custom_Plugins,plugin>>.
+For example, see 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java[`XmlConfigurationFactory.java`]
 and 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java[`XmlConfiguration.java`]
 of Log4j Core.
+
+You can use xref:manual/systemproperties.adoc#log4j2.configurationFactory[the 
`log4j2.configurationFactory` property] to explicitly set a 
`ConfigurationFactory` to be used before any other factory implementation.
 
 [#LoggerConfig]
-== LoggerConfig
-
-`LoggerConfig` objects are where Loggers created by applications tie into
-the configuration. The Log4j implementation requires that all
-LoggerConfigs are based on the LoggerConfig class, so applications
-wishing to make changes must do so by extending the `LoggerConfig` class.
-To declare the new `LoggerConfig`, declare it as a Plugin of type "Core"
-and providing the name that applications should specify as the element
-name in the configuration. The `LoggerConfig` should also define a
-PluginFactory that will create an instance of the `LoggerConfig`.
-
-The following example shows how the root `LoggerConfig` simply extends a
-generic `LoggerConfig`.
-
-[source,java]
-----
-@Configurable(printObject = true)
-@Plugin("root")
-public static class RootLogger extends LoggerConfig {
-
-    @PluginFactory
-    public static LoggerConfig 
createLogger(@PluginAttribute(defaultBooleanValue = true) boolean additivity,
-                                            
@PluginAttribute(defaultStringValue = "ERROR") Level level,
-                                            @PluginElement AppenderRef[] refs,
-                                            @PluginElement Filter filter) {
-        List<AppenderRef> appenderRefs = Arrays.asList(refs);
-        return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, 
filter, level, additivity);
-    }
-}
-----
+=== `LoggerConfig`
 
-[#LogEventFactory]
-== LogEventFactory
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/LoggerConfig.html[`LoggerConfig`]
 denotes the `Logger` configurations in a `Configuration`.
+A custom `LoggerConfig` needs to suffice following conditions:
 
-A LogEventFactory is used to generate LogEvents. Applications may replace the 
standard LogEventFactory by setting the value of the system property 
Log4jLogEventFactory to the name of the custom LogEventFactory class.
+* It needs to extend from `LoggerConfig` class
+* It needs to be declared as a <<Custom_Plugins,plugin>>
+** Its plugin `category` should be set to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Node.html#CATEGORY[`Node.CATEGORY`]
 
-Note: When log4j is configured to have xref:manual/async.adoc#AllAsync[all
-loggers asynchronous], log events are pre-allocated in a ring buffer and
-the `LogEventFactory` is not used.
+For example, see `RootLogger` definition in 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java[`LoggerConfig.java`].
 
-[#MessageFactory]
-== MessageFactory
+[#LogEventFactory]
+=== `LogEventFactory`
 
-A `MessageFactory` is used to generate `Message` objects. Applications may
-replace the standard `ReusableMessageFactory` by setting the value of the
-system property `log4j2.messageFactory` to the name of the custom
-`MessageFactory` class.
+Log4j Core uses 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/LogEventFactory.html[`LogEventFactory`]
 to create 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`]s.
+You can replace the default `LogEventFactory` implementation with a custom one 
of yours by using xref:manual/systemproperties.adoc#log4j2.logEventFactory[the 
`log4j2.logEventFactory` property].
 
-Flow messages for the `Logger.entry()` and `Logger.exit()` methods have
-a separate `FlowMessageFactory`. Applications may replace the
-`DefaultFlowMessageFactory` by setting the value of the system property
-`log4j2.flowMessageFactory` to the name of the custom `FlowMessageFactory`
-class.
+[NOTE]
+====
+xref:manual/async.adoc[] discard `LogEventFactory` and any configuration 
related with it.
+====
 
-[#Custom_Plugins]
-== Custom Plugins
+[#MessageFactory]
+=== `MessageFactory2`
+
+Log4j Core uses 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/MessageFactory2.html[`MessageFactory2`]
 to create 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/Message.html[`Message`]s.
+You can replace the default `MessageFactory2` implementation with a custom one 
of yours by using xref:manual/systemproperties.adoc#log4j2.messageFactory[the 
`log4j2.messageFactory` property].
 
-// TODO
-See the xref:manual/plugins.adoc[Plugins] section of the manual.
+In the case of xref:manual/flowtracing.adoc[], Log4j Core uses 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/FlowMessageFactory.html[`FlowMessageFactory`].
+You can replace the default `FlowMessageFactory` implementation with a custom 
one of yours by using 
xref:manual/systemproperties.adoc#log4j2.flowMessageFactory[the 
`log4j2.flowMessageFactory` property].
diff --git a/src/site/antora/modules/ROOT/pages/manual/plugins.adoc 
b/src/site/antora/modules/ROOT/pages/manual/plugins.adoc
index f8beb69933..67dad5c9f2 100644
--- a/src/site/antora/modules/ROOT/pages/manual/plugins.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/plugins.adoc
@@ -47,18 +47,20 @@ In this section we will give an overview of the Log4j 
plugin system by answering
 A class can be declared as a plugin by adding a 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/Plugin.html[`@Plugin`]
 annotation, which is essentially composed of following attributes:
 
 `name`::
-Denotes the name of the plugin and is recommended to be distinct among plugins 
sharing the same `category`.
+Name of the plugin.
+It is recommended to be distinct among plugins sharing the same `category`.
 `name` matching is case-insensitive.
 
-`category`::
+`category` (optional)::
 A name used for grouping a set of plugins.
-`name` matching is case-sensitive.
+`category` matching is case-sensitive.
 
-`elementType`::
+`elementType` (optional)::
 Name of the corresponding category of the xref:manual/configuration.adoc[Log4j 
configuration] file element this plugin belongs under.
 You can omit this attribute if your plugin is not meant to be represented in a 
configuration file.
 
-For example, xref:manual/lookups.adoc#extending[lookups] only use the 
`category` attribute and set it to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html#CATEGORY[`StrLookup.CATEGORY`]
 (`Lookup`).
+We will try to explain when to use `category` and `elementType` attributes 
with an example.
+xref:manual/lookups.adoc#extending[Lookups] only use the `category` attribute 
and set it to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html#CATEGORY[`StrLookup.CATEGORY`]
 (`Lookup`).
 On the other hand, xref:manual/appenders.adoc#extending[appenders] use both 
the `category` and `elementType` attributes and set them to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Node.html#CATEGORY[`Node.CATEGORY`]
 (`Core`) and 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html#ELEMENT_TYPE[`Appender.ELEMENT_TYPE`]
 (`appender`), respectively.
 The reason appenders use an `elementType` and lookups don't is that appenders 
need to be referred to in an element in a Log4j configuration file (e.g., 
`log4j2.xml`) whereas lookups don't.
 See <<core>> for details.
@@ -160,7 +162,7 @@ Each attribute or element annotation must include the name 
that must be present
 For plugin builders, the names of the fields will be used by default if no 
name is specified in the annotation.
 
 [#type-converters]
-=== Plugin factory attribute type converters
+==== Plugin factory attribute type converters
 
 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.html[`TypeConverter`]s
 are a certain group of plugins for converting ``String``s read from 
configuration file elements into the types used in plugin factory attributes.
 Other plugins can already be injected via <<PluginElement,the `@PluginElement` 
annotation>>; now, any type supported by ``TypeConverter``s can be used in a 
`@PluginAttribute`-annotated factory attribute.

Reply via email to