diff --git a/common/source/java/ch/systemsx/cisd/common/mail/JavaMailProperties.java b/common/source/java/ch/systemsx/cisd/common/mail/JavaMailProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..d99365ab76d6b6127fc2b6d2c21b9cc1472d3322
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/mail/JavaMailProperties.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.mail;
+
+/**
+ * The <i>JavaMail API</i> supports the following standard properties.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class JavaMailProperties
+{
+
+    private JavaMailProperties()
+    {
+        // Can not be instantiated.
+    }
+
+    /** Specifies the default message access protocol. */
+    public static final String MAIL_TRANSPORT_PROTOCOL = "mail.transport.protocol";
+
+    /** The initial debug mode. */
+    public static final String MAIL_DEBUG = "mail.debug";
+
+    /** The return email address of the current user. */
+    public static final String MAIL_FROM = "mail.from";
+
+    /** The default host name of the mail server for Transports. */
+    public static final String MAIL_SMTP_HOST = "mail.smtp.host";
+
+    /** The default user name to use when connecting to the mail server. */
+    public static final String MAIL_SMTP_USER = "mail.smtp.user";
+
+    /** Whether authentication is needed when connecting to the mail server. */
+    public static final String MAIL_SMTP_AUTH = "mail.smtp.auth";
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/mail/MailClient.java b/common/source/java/ch/systemsx/cisd/common/mail/MailClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..7296e42063bdcf8ecadfee4caf086c393e9595e3
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/mail/MailClient.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.mail;
+
+import java.util.Arrays;
+import java.util.Properties;
+
+import javax.mail.Authenticator;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.PasswordAuthentication;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+
+/**
+ * A small mail client that simplifies the sending of emails using of <i>JavaMail API</i>.
+ * <p>
+ * Just instantiate this class and use {@link #sendMessage(String, String, String[])} to send the email via SMTP.
+ * </p>
+ * 
+ * @author Christian Ribeaud
+ */
+public final class MailClient extends Authenticator
+{
+
+    /** This system property is not supported by the <i>JavaMail API</i> */
+    public final static String MAIL_SMTP_PASSWORD = "mail.smtp.user";
+
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, MailClient.class);
+
+    private final String smtpUsername;
+
+    private final String smtpPassword;
+
+    private final String smtpHost;
+
+    private final String from;
+
+    public MailClient(final String from, final String smtpHost)
+    {
+        this(from, smtpHost, null, null);
+    }
+
+    public MailClient(Properties properties)
+    {
+        this(properties.getProperty(JavaMailProperties.MAIL_FROM), properties
+                .getProperty(JavaMailProperties.MAIL_SMTP_HOST), properties
+                .getProperty(JavaMailProperties.MAIL_SMTP_USER), properties.getProperty(MAIL_SMTP_PASSWORD));
+    }
+
+    public MailClient(final String from, final String smtpHost, final String smtpUsername, final String smtpPassword)
+    {
+        assert from != null;
+        assert smtpHost != null;
+
+        this.from = from;
+        this.smtpHost = smtpHost;
+        this.smtpUsername = smtpUsername;
+        this.smtpPassword = smtpPassword;
+    }
+
+    private final Properties createProperties()
+    {
+        Properties properties = null;
+        try
+        {
+            properties = new Properties(System.getProperties());
+        } catch (SecurityException ex)
+        {
+            properties = new Properties();
+        }
+        if (smtpUsername != null)
+        {
+            properties.put(JavaMailProperties.MAIL_SMTP_USER, smtpUsername);
+        }
+        if (smtpHost != null)
+        {
+            properties.put(JavaMailProperties.MAIL_SMTP_HOST, smtpHost);
+        }
+        if (smtpPassword != null && smtpUsername != null)
+        {
+            properties.put(JavaMailProperties.MAIL_SMTP_AUTH, Boolean.TRUE.toString());
+        }
+        properties.put(JavaMailProperties.MAIL_DEBUG, operationLog.isDebugEnabled() ? Boolean.TRUE.toString()
+                : Boolean.FALSE.toString());
+        properties.put(JavaMailProperties.MAIL_TRANSPORT_PROTOCOL, "smtp");
+        return properties;
+    }
+
+    private final Session createSession()
+    {
+        Properties properties = createProperties();
+        if (operationLog.isDebugEnabled())
+        {
+            operationLog.debug("Creating mail session with following properties '" + properties + "'.");
+        }
+        boolean mailSmtpAuth = Boolean.parseBoolean(properties.getProperty(JavaMailProperties.MAIL_SMTP_AUTH));
+        Session session = Session.getInstance(properties, mailSmtpAuth ? this : null);
+        session.setDebug(operationLog.isDebugEnabled());
+        return session;
+    }
+
+    private final static InternetAddress createInternetAddress(String internetAddress)
+    {
+        try
+        {
+            return new InternetAddress(internetAddress);
+        } catch (AddressException e)
+        {
+            operationLog.error("Could not parse address [" + internetAddress + "].", e);
+            return null;
+        }
+    }
+
+    /**
+     * Sends a mail with given <var>subject</var> and <var>content</var> to given <var>recipients</var>.
+     * 
+     * @param recipients list of recipients (of type <code>Message.RecipientType.TO</code>)
+     */
+    public final void sendMessage(String subject, String content, String... recipients) throws MessagingException
+    {
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info("SENDING message from '" + from + "' to recipients '" + Arrays.asList(recipients) + "'");
+        }
+        int len = recipients.length;
+        InternetAddress[] internetAddresses = new InternetAddress[len];
+        for (int i = 0; i < len; i++)
+        {
+            internetAddresses[i] = createInternetAddress(recipients[i]);
+        }
+        MimeMessage msg = new MimeMessage(createSession());
+        msg.setFrom(createInternetAddress(from));
+        msg.addRecipients(Message.RecipientType.TO, internetAddresses);
+        msg.setSubject(subject);
+        msg.setText(content);
+        Transport.send(msg);
+    }
+
+    //
+    // Authenticator
+    //
+
+    @Override
+    protected final PasswordAuthentication getPasswordAuthentication()
+    {
+        return new PasswordAuthentication(smtpUsername, smtpPassword);
+    }
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/ExtendedProperties.java b/common/source/java/ch/systemsx/cisd/common/utilities/ExtendedProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9de6fdd7ef6dc75c38af0c2130d2620f7412029
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/ExtendedProperties.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+package ch.systemsx.cisd.common.utilities;
+
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * This implementation supports parameters substitution in property value.
+ * 
+ * @see #getProperty(String)
+ * @author Christian Ribeaud
+ */
+public final class ExtendedProperties extends Properties
+{
+    private static final long serialVersionUID = 1L;
+
+    /** Default placeholder prefix: "${" */
+    private static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
+
+    /** Default placeholder suffix: "}" */
+    private static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
+
+    /**
+     * @see java.util.Properties#Properties()
+     */
+    public ExtendedProperties()
+    {
+        super();
+    }
+
+    /**
+     * @see java.util.Properties#Properties(java.util.Properties)
+     */
+    public ExtendedProperties(Properties defs)
+    {
+        super(defs);
+    }
+
+    /**
+     * Any parameter like <code>${propertyName}</code> in property value will be replaced with the value of property
+     * with name <code>propertyName</code>.
+     * <p>
+     * For example, for the following set of properties:
+     * 
+     * <pre>
+     * param1 = abcd
+     * param2 = efgh
+     * param3 = Alphabet starts with: ${param1}${param2}
+     * </pre>
+     * 
+     * The call <code>props.getProperty("param3")</code> returns:
+     * 
+     * <pre>
+     * Alphabet starts with: abcdefgh
+     * </pre>
+     * 
+     * Note also that call <code>props.get("param3")</code> returns:
+     * 
+     * <pre>
+     * Alphabet starts with: ${param1}${param2}
+     * </pre>
+     * 
+     * So the {@link java.util.Map#get(java.lang.Object)} works as usual and returns raw (not expanded with substituted
+     * parameters) property value.
+     * </p>
+     * 
+     * @see java.util.Properties#getProperty(java.lang.String)
+     */
+    @Override
+    public String getProperty(String key)
+    {
+        String result = super.getProperty(key);
+        return result == null ? null : expandValue(result);
+    }
+
+    /**
+     * @see java.util.Properties#getProperty(java.lang.String, java.lang.String)
+     */
+    @Override
+    public String getProperty(String key, String defaultValue)
+    {
+        String result = getProperty(key);
+        return result == null ? expandValue(defaultValue) : result;
+    }
+
+    /**
+     * Returns a subset of given <code>Properties</code> based on given property key prefix.
+     * 
+     * @param prefix string, each property key should start with.
+     */
+    public final ExtendedProperties getSubset(final String prefix)
+    {
+        ExtendedProperties result = new ExtendedProperties();
+        for (Enumeration enumeration = propertyNames(); enumeration.hasMoreElements();)
+        {
+            String key = enumeration.nextElement().toString();
+            if (key.startsWith(prefix))
+            {
+                result.put(key, getProperty(key));
+            }
+        }
+        return result;
+    }
+
+    private final String expandValue(final String value)
+    {
+        if (value == null || value.length() < 4)
+        {
+            return value;
+        }
+        StringBuilder result = new StringBuilder(value.length());
+        result.append(value);
+        int p1 = result.indexOf(DEFAULT_PLACEHOLDER_PREFIX);
+        int p2 = result.indexOf(DEFAULT_PLACEHOLDER_SUFFIX, p1 + 2);
+        while (p1 >= 0 && p2 > p1)
+        {
+            String paramName = result.substring(p1 + 2, p2);
+            String paramValue = getProperty(paramName);
+            if (paramValue != null)
+            {
+                result.replace(p1, p2 + 1, paramValue);
+                p1 += paramValue.length();
+            } else
+            {
+                p1 = p2 + 1;
+            }
+            p1 = result.indexOf(DEFAULT_PLACEHOLDER_PREFIX, p1);
+            p2 = result.indexOf(DEFAULT_PLACEHOLDER_SUFFIX, p1 + 2);
+        }
+        return result.toString();
+    }
+}
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ExtendedPropertiesTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ExtendedPropertiesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c942233a8ef1f32019dfc096ca1b0ad9e5f09a13
--- /dev/null
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ExtendedPropertiesTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.utilities;
+
+import static org.testng.AssertJUnit.*;
+
+import java.util.Properties;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for the {@link ExtendedProperties} class.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class ExtendedPropertiesTest
+{
+    private ExtendedProperties extendedProperties;
+    
+    @BeforeMethod
+    public final void setUp() {
+        Properties props = new Properties();
+        props.setProperty("one", "eins");
+        props.setProperty("un", "${one}");
+        props.setProperty("two", "zwei");
+        props.setProperty("three", "drei");
+        extendedProperties = new ExtendedProperties(props);
+    }
+    
+    @Test
+    public final void testGetPropertyString()
+    {
+        assertEquals("eins", extendedProperties.getProperty("one"));
+        assertEquals("eins", extendedProperties.getProperty("un"));
+    }
+
+    @Test
+    public final void testGetSubsetString()
+    {
+        ExtendedProperties props = extendedProperties.getSubset("t");
+        assert props.size() == 2;
+        assert props.getProperty("two").equals("zwei");
+        props = extendedProperties.getSubset("un");
+        assert props.size() == 1;
+        assert props.getProperty("un").equals("eins");
+    }
+
+}