pgoldstein    2002/09/24 15:03:13

  Modified:    www/javadocs overview-frame.html package-list packages.html
                        overview-summary.html
               src/java/org/apache/james/fetchpop FetchPOP.java
                        FetchScheduler.java FetchScheduler.xinfo
  Added:       src/java/org/apache/james/fetchpop package.html
  Log:
  Correcting spelling error.
  Adding comments.
  Refactoring of code to make it more "Avalon"-ish
  Added cleanup so the fetch tasks are properly removed from the TimeScheduler
  Adding javadocs.
  Updating package list.
  
  
  Revision  Changes    Path
  1.7       +7 -1      jakarta-james/www/javadocs/overview-frame.html
  
  Index: overview-frame.html
  ===================================================================
  RCS file: /home/cvs/jakarta-james/www/javadocs/overview-frame.html,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- overview-frame.html       14 Sep 2002 09:10:56 -0000      1.6
  +++ overview-frame.html       24 Sep 2002 22:03:12 -0000      1.7
  @@ -2,7 +2,7 @@
   <!--NewPage-->
   <HTML>
   <HEAD>
  -<!-- Generated by javadoc on Sat Sep 14 02:01:41 PDT 2002 -->
  +<!-- Generated by javadoc on Tue Sep 24 13:09:50 PDT 2002 -->
   <TITLE>
   Overview (James API)
   </TITLE>
  @@ -38,6 +38,8 @@
   <BR>
   <FONT CLASS="FrameItemFont"><A HREF="org/apache/james/dnsserver/package-frame.html" 
TARGET="packageFrame">org.apache.james.dnsserver</A></FONT>
   <BR>
  +<FONT CLASS="FrameItemFont"><A HREF="org/apache/james/fetchpop/package-frame.html" 
TARGET="packageFrame">org.apache.james.fetchpop</A></FONT>
  +<BR>
   <FONT CLASS="FrameItemFont"><A 
HREF="org/apache/james/mailrepository/package-frame.html" 
TARGET="packageFrame">org.apache.james.mailrepository</A></FONT>
   <BR>
   <FONT CLASS="FrameItemFont"><A 
HREF="org/apache/james/nntpserver/package-frame.html" 
TARGET="packageFrame">org.apache.james.nntpserver</A></FONT>
  @@ -68,7 +70,11 @@
   <BR>
   <FONT CLASS="FrameItemFont"><A HREF="org/apache/james/util/package-frame.html" 
TARGET="packageFrame">org.apache.james.util</A></FONT>
   <BR>
  +<FONT CLASS="FrameItemFont"><A 
HREF="org/apache/james/util/connection/package-frame.html" 
TARGET="packageFrame">org.apache.james.util.connection</A></FONT>
  +<BR>
   <FONT CLASS="FrameItemFont"><A 
HREF="org/apache/james/util/mordred/package-frame.html" 
TARGET="packageFrame">org.apache.james.util.mordred</A></FONT>
  +<BR>
  +<FONT CLASS="FrameItemFont"><A 
HREF="org/apache/james/util/watchdog/package-frame.html" 
TARGET="packageFrame">org.apache.james.util.watchdog</A></FONT>
   <BR>
   <FONT CLASS="FrameItemFont"><A HREF="org/apache/mailet/package-frame.html" 
TARGET="packageFrame">org.apache.mailet</A></FONT>
   <BR>
  
  
  
  1.6       +3 -0      jakarta-james/www/javadocs/package-list
  
  Index: package-list
  ===================================================================
  RCS file: /home/cvs/jakarta-james/www/javadocs/package-list,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- package-list      14 Sep 2002 09:10:56 -0000      1.5
  +++ package-list      24 Sep 2002 22:03:12 -0000      1.6
  @@ -2,6 +2,7 @@
   org.apache.james.context
   org.apache.james.core
   org.apache.james.dnsserver
  +org.apache.james.fetchpop
   org.apache.james.mailrepository
   org.apache.james.nntpserver
   org.apache.james.nntpserver.repository
  @@ -17,5 +18,7 @@
   org.apache.james.transport.matchers
   org.apache.james.userrepository
   org.apache.james.util
  +org.apache.james.util.connection
   org.apache.james.util.mordred
  +org.apache.james.util.watchdog
   org.apache.mailet
  
  
  
  1.7       +1 -1      jakarta-james/www/javadocs/packages.html
  
  Index: packages.html
  ===================================================================
  RCS file: /home/cvs/jakarta-james/www/javadocs/packages.html,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- packages.html     14 Sep 2002 09:10:56 -0000      1.6
  +++ packages.html     24 Sep 2002 22:03:12 -0000      1.7
  @@ -2,7 +2,7 @@
   <!--NewPage-->
   <HTML>
   <HEAD>
  -<!-- Generated by javadoc on Sat Sep 14 02:01:41 PDT 2002 -->
  +<!-- Generated by javadoc on Tue Sep 24 13:09:50 PDT 2002 -->
   <TITLE>
   James API
   </TITLE>
  
  
  
  1.7       +13 -1     jakarta-james/www/javadocs/overview-summary.html
  
  Index: overview-summary.html
  ===================================================================
  RCS file: /home/cvs/jakarta-james/www/javadocs/overview-summary.html,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- overview-summary.html     14 Sep 2002 09:10:56 -0000      1.6
  +++ overview-summary.html     24 Sep 2002 22:03:12 -0000      1.7
  @@ -2,7 +2,7 @@
   <!--NewPage-->
   <HTML>
   <HEAD>
  -<!-- Generated by javadoc on Sat Sep 14 02:01:41 PDT 2002 -->
  +<!-- Generated by javadoc on Tue Sep 24 13:09:50 PDT 2002 -->
   <TITLE>
   Overview (James API)
   </TITLE>
  @@ -91,6 +91,10 @@
   <TD>Provides classes implementing simple DNS facilities for James</TD>
   </TR>
   <TR BGCOLOR="white" CLASS="TableRowColor">
  +<TD WIDTH="20%"><B><A 
HREF="org/apache/james/fetchpop/package-summary.html">org.apache.james.fetchpop</A></B></TD>

  +<TD>Provides classes implementing fetch POP functionality.  </TD>
  +</TR>
  +<TR BGCOLOR="white" CLASS="TableRowColor">
   <TD WIDTH="20%"><B><A 
HREF="org/apache/james/mailrepository/package-summary.html">org.apache.james.mailrepository</A></B></TD>

   <TD>Implementations of mail repositories for use in James.</TD>
   </TR>
  @@ -151,7 +155,15 @@
   <TD>A variety of utility classes used inside James.</TD>
   </TR>
   <TR BGCOLOR="white" CLASS="TableRowColor">
  +<TD WIDTH="20%"><B><A 
HREF="org/apache/james/util/connection/package-summary.html">org.apache.james.util.connection</A></B></TD>

  +<TD>Provides classes that implement Avalon Cornerstone connection services.  </TD>
  +</TR>
  +<TR BGCOLOR="white" CLASS="TableRowColor">
   <TD WIDTH="20%"><B><A 
HREF="org/apache/james/util/mordred/package-summary.html">org.apache.james.util.mordred</A></B></TD>

  +<TD>&nbsp;</TD>
  +</TR>
  +<TR BGCOLOR="white" CLASS="TableRowColor">
  +<TD WIDTH="20%"><B><A 
HREF="org/apache/james/util/watchdog/package-summary.html">org.apache.james.util.watchdog</A></B></TD>

   <TD>&nbsp;</TD>
   </TR>
   <TR BGCOLOR="white" CLASS="TableRowColor">
  
  
  
  1.2       +87 -56    jakarta-james/src/java/org/apache/james/fetchpop/FetchPOP.java
  
  Index: FetchPOP.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/fetchpop/FetchPOP.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FetchPOP.java     24 Sep 2002 15:36:30 -0000      1.1
  +++ FetchPOP.java     24 Sep 2002 22:03:12 -0000      1.2
  @@ -1,13 +1,9 @@
  -/**
  - * FetchPOP.java
  - * 
  - * Copyright (C) 24-Sep-2002 The Apache Software Foundation. All rights reserved.
  +/*
  + * Copyright (C) The Apache Software Foundation. All rights reserved.
    *
    * This software is published under the terms of the Apache Software License
    * version 1.1, a copy of which has been included with this distribution in
  - * the LICENSE file. 
  - *
  - * Danny Angus
  + * the LICENSE file.
    */
   package org.apache.james.fetchpop;
   import java.io.IOException;
  @@ -20,62 +16,96 @@
   import javax.mail.internet.MimeMessage;
   
   import org.apache.avalon.cornerstone.services.scheduler.Target;
  +import org.apache.avalon.framework.component.ComponentException;
  +import org.apache.avalon.framework.component.ComponentManager;
  +import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.component.DefaultComponentManager;
  +import org.apache.avalon.framework.configuration.Configurable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  -import org.apache.avalon.framework.logger.Logger;
  +import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.commons.net.pop3.POP3Client;
   import org.apache.commons.net.pop3.POP3MessageInfo;
   import org.apache.james.services.MailServer;
   /**
    *
  - * A class which fetches mail from a single POP account and inserts it into the 
incoming spool<br>
  + * A class which fetches mail from a single POP account and inserts it 
  + * into the incoming spool<br>
  + *
    * <br>$Id$
    * @author <A href="mailto:[EMAIL PROTECTED]";>Danny Angus</a>
    * 
    */
  -public class FetchPOP implements Target {
  -    private Configuration conf;
  -    private DefaultComponentManager compMgr;
  +public class FetchPOP extends AbstractLogEnabled implements Configurable, Target {
  +
  +    /**
  +     * The MailServer service
  +     */
       private MailServer server;
  +
  +    /**
  +     * The unique, identifying name for this task
  +     */
  +    private String fetchTaskName;
  +
  +    /**
  +     * The POP3 server host name for this fetch task
  +     */
       private String popHost;
  +
  +    /**
  +     * The POP3 user name for this fetch task
  +     */
       private String popUser;
  +
  +    /**
  +     * The POP3 user password for this fetch task
  +     */
       private String popPass;
  -    private String popName;
  -    private Logger logger;
  +
       /**
        * @see 
org.apache.avalon.cornerstone.services.scheduler.Target#targetTriggered(String)
        */
       public void targetTriggered(String arg0) {
  -        getLogger().debug(popName + " fetcher starting fetch");
  +        if (getLogger().isDebugEnabled()) {
  +            getLogger().debug(fetchTaskName + " fetcher starting fetch");
  +        }
           POP3Client pop = new POP3Client();
           try {
               pop.connect(popHost);
               pop.login(popUser, popPass);
  -            getLogger().debug("login:" + pop.getReplyString());
  +            if (getLogger().isDebugEnabled()) {
  +                getLogger().debug("Login:" + pop.getReplyString());
  +            }
               pop.setState(POP3Client.TRANSACTION_STATE);
               POP3MessageInfo[] messages = pop.listMessages();
  -            getLogger().debug("list:" + pop.getReplyString());
  -            Vector recieved = new Vector();
  +            getLogger().debug("List:" + pop.getReplyString());
  +            Vector received = new Vector();
               for (int i = 0; i < messages.length; i++) {
                   InputStream in = new 
ReaderInputStream(pop.retrieveMessage(messages[i].number));
  -                getLogger().debug("retrieve:" + pop.getReplyString());
  +                getLogger().debug("Retrieve:" + pop.getReplyString());
                   MimeMessage message = new MimeMessage(null, in);
                   in.close();
  -                message.addHeader("X-fetchpop", "fetched by james");
  +                message.addHeader("X-fetchpop", "Fetched by James");
                   message.saveChanges();
  -                logger.debug("sent message " + message.toString());
  +                if (getLogger().isDebugEnabled()) {
  +                    getLogger().debug("Sent message " + message.toString());
  +                }
                   server.sendMail(message);
  -                recieved.add(messages[i]);
  +                received.add(messages[i]);
               }
  -            Enumeration enum = recieved.elements();
  +            Enumeration enum = received.elements();
               while (enum.hasMoreElements()) {
                   POP3MessageInfo element = (POP3MessageInfo) enum.nextElement();
                   pop.deleteMessage(element.number);
  -                getLogger().debug("delete:" + pop.getReplyString());
  +                if (getLogger().isDebugEnabled()) {
  +                    getLogger().debug("Delete:" + pop.getReplyString());
  +                }
               }
               pop.logout();
  -            getLogger().debug("logout:" + pop.getReplyString());
  +            if (getLogger().isDebugEnabled()) {
  +                getLogger().debug("logout:" + pop.getReplyString());
  +            }
               pop.disconnect();
           } catch (SocketException e) {
               getLogger().error(e.getMessage());
  @@ -85,39 +115,40 @@
               getLogger().error(e.getMessage());
           }
       }
  +
  +    /**
  +     * Pass the <code>ComponentManager</code> to the instance.
  +     * The instance uses the specified <code>ComponentManager</code> to 
  +     * acquire the components it needs for execution.
  +     *
  +     * @param componentManager The <code>ComponentManager</code> which this
  +     *                <code>Composable</code> uses.
  +     * @throws ComponentException if an error occurs
  +     */
  +    public void compose( final ComponentManager componentManager )
  +        throws ComponentException {
  +        try {
  +            server = (MailServer) componentManager.lookup(MailServer.ROLE);
  +        } catch (ClassCastException cce) {
  +            StringBuffer errorBuffer =
  +                new StringBuffer(128)
  +                        .append("Component ")
  +                        .append(MailServer.ROLE)
  +                        .append("does not implement the required interface.");
  +            throw new ComponentException(errorBuffer.toString());
  +        }
  +    }
  +
       /**
  -     * Method configure.
  -     * &lt;fetchpop enabled="false"&gt;<br>
  -     *  &lt;!-- you can have as many fetch tasks as you want to        --&gt;<br>
  -     *  &lt;!-- but each must have a unique name to identify itself by --&gt;<br>
  -     *  &lt;fetch name="mydomain.com"&gt;<br>
  -     *      &lt;!-- host name or IP address --&gt;<br>
  -     *      &lt;host&gt;mail.mydomain.com&lt;/host&gt;<br>
  -     *      &lt;!-- acount login username --&gt;<br>
  -     *      &lt;user&gt;username&lt;/user&gt;<br>
  -     *      &lt;!-- account login password --&gt;<br>
  -     *      &lt;password&gt;pass&lt;/password&gt;<br>
  -     *      &lt;!-- Interval to check this account in milliseconds, 60000 is every 
ten minutes --&gt;<br>
  -     *      &lt;interval&gt;600000&lt;/interval&gt;<br>
  -     *  &lt;/fetch&gt;<br>
  -     *  &lt;/fetchpop&gt;<br>
  -     *  @param conf configuration element for this fetcher:<br>
  -     * @param server mailserver which can spool fetched mail
  -     * @param logger child logger of FetchScheduler
  -     * @throws ConfigurationException
  -     */
  -    public void configure(Configuration conf, MailServer server, Logger logger)
  -        throws ConfigurationException {
  -        logger.debug("configured fetch");
  -        this.conf = conf;
  -        this.server = server;
  -        this.logger = logger;
  +     * @see 
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
  +     */
  +    public void configure(Configuration conf) throws ConfigurationException {
           this.popHost = conf.getChild("host").getValue();
           this.popUser = conf.getChild("user").getValue();
           this.popPass = conf.getChild("password").getValue();
  -        this.popName = conf.getAttribute("name");
  -    }
  -    private Logger getLogger() {
  -        return logger;
  +        this.fetchTaskName = conf.getAttribute("name");
  +        if (getLogger().isDebugEnabled()) {
  +            getLogger().debug("Configured FetchPOP");
  +        }
       }
   }
  
  
  
  1.2       +66 -21    
jakarta-james/src/java/org/apache/james/fetchpop/FetchScheduler.java
  
  Index: FetchScheduler.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/fetchpop/FetchScheduler.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FetchScheduler.java       24 Sep 2002 15:36:30 -0000      1.1
  +++ FetchScheduler.java       24 Sep 2002 22:03:12 -0000      1.2
  @@ -1,17 +1,14 @@
  -/**
  - * FetchScheduler.java
  - * 
  - * Copyright (C) 24-Sep-2002 The Apache Software Foundation. All rights reserved.
  +/*
  + * Copyright (C) The Apache Software Foundation. All rights reserved.
    *
    * This software is published under the terms of the Apache Software License
    * version 1.1, a copy of which has been included with this distribution in
  - * the LICENSE file. 
  - *
  - * Danny Angus
  + * the LICENSE file.
    */
   package org.apache.james.fetchpop;
   import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger;
   import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler;
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.activity.Initializable;
   import org.apache.avalon.framework.component.Component;
   import org.apache.avalon.framework.component.ComponentException;
  @@ -23,6 +20,10 @@
   import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.james.services.MailServer;
  +
  +import java.util.ArrayList;
  +import java.util.Iterator;
  +
   /**
    *  A class to instantiate and schedule a set of POP mail fetching tasks<br>
    * <br>$Id$
  @@ -32,33 +33,63 @@
    */
   public class FetchScheduler
       extends AbstractLogEnabled
  -    implements Component, Configurable, Initializable, Composable {
  +    implements Component, Composable, Configurable, Initializable, Disposable {
  +
  +    /**
  +     * Configuration object for this service
  +     */
       private Configuration conf;
  -    private MailServer server;
  -    private DefaultComponentManager compMgr;
  +
  +    /**
  +     * The component manager that allows access to the system services
  +     */
  +    private ComponentManager compMgr;
  +
  +    /**
  +     * The scheduler service that is used to trigger fetch tasks.
  +     */
  +    private TimeScheduler scheduler;
  +
  +    /**
  +     * Whether this service is enabled.
  +     */
  +    private volatile boolean enabled = false;
  +
  +    private ArrayList theFetchTaskNames = new ArrayList();
  +
  +    /**
  +     * @see 
org.apache.avalon.framework.component.Composable#compose(ComponentManager)
  +     */
  +    public void compose(ComponentManager comp) throws ComponentException {
  +        compMgr = comp;
  +    }
  +
       /**
        * @see 
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
        */
       public void configure(Configuration conf) throws ConfigurationException {
           this.conf = conf;
       }
  +
       /**
        * @see org.apache.avalon.framework.activity.Initializable#initialize()
        */
       public void initialize() throws Exception {
  -        if (conf.getAttribute("enabled").equalsIgnoreCase("true")) {
  -            TimeScheduler scheduler = (TimeScheduler) 
compMgr.lookup(TimeScheduler.ROLE);
  +        enabled = conf.getAttributeAsBoolean("enabled", false);
  +        if (enabled) {
  +            scheduler = (TimeScheduler) compMgr.lookup(TimeScheduler.ROLE);
               Configuration[] fetchConfs = conf.getChildren("fetch");
               for (int i = 0; i < fetchConfs.length; i++) {
                   FetchPOP fp = new FetchPOP();
                   Configuration fetchConf = fetchConfs[i];
  -                fp.configure(
  -                    fetchConf,
  -                    (MailServer) compMgr.lookup(MailServer.ROLE),
  -                    getLogger().getChildLogger(fetchConf.getAttribute("name")));
  +                String fetchTaskName = fetchConf.getAttribute("name");
  +                fp.enableLogging(getLogger().getChildLogger(fetchTaskName));
  +                fp.compose(compMgr);
  +                fp.configure(fetchConf);
                   Integer interval = new 
Integer(fetchConf.getChild("interval").getValue());
                   PeriodicTimeTrigger fetchTrigger = new PeriodicTimeTrigger(0, 
interval.intValue());
  -                scheduler.addTrigger(fetchConf.getAttribute("name"), fetchTrigger, 
fp);
  +                scheduler.addTrigger(fetchTaskName, fetchTrigger, fp);
  +                theFetchTaskNames.add(fetchTaskName);
               }
               System.out.println("Fetch POP Started ");
           } else {
  @@ -66,10 +97,24 @@
               System.out.println("Fetch POP Disabled");
           }
       }
  +
       /**
  -     * @see 
org.apache.avalon.framework.component.Composable#compose(ComponentManager)
  +     * The dispose operation is called at the end of a components lifecycle.
  +     * Instances of this class use this method to release and destroy any
  +     * resources that they own.
  +     *
  +     * @throws Exception if an error is encountered during shutdown
        */
  -    public void compose(ComponentManager comp) throws ComponentException {
  -        compMgr = new DefaultComponentManager(comp);
  +    public void dispose() {
  +        if (enabled) {
  +            getLogger().info( "Fetch POP dispose..." );
  +            Iterator nameIterator = theFetchTaskNames.iterator();
  +            while (nameIterator.hasNext()) {
  +                scheduler.removeTrigger((String)nameIterator.next());
  +            }
  +
  +            getLogger().info( "Fetch POP ...dispose end" );
  +        }
       }
  +
   }
  
  
  
  1.2       +23 -23    
jakarta-james/src/java/org/apache/james/fetchpop/FetchScheduler.xinfo
  
  Index: FetchScheduler.xinfo
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/fetchpop/FetchScheduler.xinfo,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FetchScheduler.xinfo      24 Sep 2002 15:36:30 -0000      1.1
  +++ FetchScheduler.xinfo      24 Sep 2002 22:03:12 -0000      1.2
  @@ -1,23 +1,23 @@
  -<?xml version="1.0"?>
  -
  -<blockinfo>
  -
  -  <!-- section to describe block -->
  -  <block>
  -    <version>1.0</version>
  -  </block>
  -
  -  <!-- services that are offered by this block -->
  -  <services>
  -    <service name="org.apache.avalon.framework.component.Component" version="1.0"/>
  -  </services>
  -
  -  <dependencies>
  -    <dependency>
  -      <service name="org.apache.james.services.MailServer" version="1.0"/>
  -    </dependency>
  -    <dependency> 
  -      <service 
name="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler" version="1.0"/>
  -    </dependency> 
  -  </dependencies>  
  -</blockinfo>
  +<?xml version="1.0"?>
  +
  +<blockinfo>
  +
  +  <!-- section to describe block -->
  +  <block>
  +    <version>1.0</version>
  +  </block>
  +
  +  <!-- services that are offered by this block -->
  +  <services>
  +    <service name="org.apache.avalon.framework.component.Component" version="1.0"/>
  +  </services>
  +
  +  <dependencies>
  +    <dependency>
  +      <service name="org.apache.james.services.MailServer" version="1.0"/>
  +    </dependency>
  +    <dependency> 
  +      <service 
name="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler" version="1.0"/>
  +    </dependency> 
  +  </dependencies>  
  +</blockinfo>
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/fetchpop/package.html
  
  Index: package.html
  ===================================================================
  <body>
  <p>Provides classes implementing fetch POP functionality.  This functionality allows 
consolidation of messages from a number of POP3 servers so that they reside on a 
single James server.</p>
  </body>
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to