diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/Email.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/Email.java
new file mode 100644
index 0000000000000000000000000000000000000000..2beefd20584d51b2e5be21fa08efa04586cf5970
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/Email.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking;
+
+import ch.systemsx.cisd.common.mail.IMailClient;
+
+/**
+ * Simple encapsulation of
+ * {@link IMailClient#sendMessage(String, String, String, ch.systemsx.cisd.common.mail.From, String...)}
+ * method parameters.
+ * 
+ * @author Piotr Buczek
+ */
+public class Email
+{
+    private final String subject;
+
+    private final String content;
+
+    private final String replyToOrNull;
+
+    private final String fromOrNull;
+
+    private final String[] recipients;
+
+    public Email(String subject, String content, String replyToOrNull, String fromOrNull,
+            String... recipients)
+    {
+        super();
+        this.subject = subject;
+        this.content = content;
+        this.replyToOrNull = replyToOrNull;
+        this.fromOrNull = fromOrNull;
+        this.recipients = recipients;
+    }
+
+    public String getSubject()
+    {
+        return subject;
+    }
+
+    public String getContent()
+    {
+        return content;
+    }
+
+    public String getReplyToOrNull()
+    {
+        return replyToOrNull;
+    }
+
+    public String getFromOrNull()
+    {
+        return fromOrNull;
+    }
+
+    public String[] getRecipients()
+    {
+        return recipients;
+    }
+
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/EntityTrackingEmailData.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/EntityTrackingEmailData.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0d1dd9a371093ec29d6324df7cf14c02fd178e2
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/EntityTrackingEmailData.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+
+/**
+ * Structure containing all data about tracked entities that will be used in a single email to an
+ * recipient. Its purpose is to group data that will be used to generate content of an email
+ * containing merged information about all events that the recipient should be notified about.
+ * 
+ * @author Piotr Buczek
+ */
+public class EntityTrackingEmailData
+{
+    public static class SequencingSampleData
+    {
+        private final boolean newlyTracked;
+
+        private final Sample sequencingSample;
+
+        private final List<Sample> flowLaneSamples = new ArrayList<Sample>(0);
+
+        public SequencingSampleData(Sample sequencingSample, boolean newlyTracked)
+        {
+            super();
+            this.sequencingSample = sequencingSample;
+            this.newlyTracked = newlyTracked;
+        }
+
+        public void addFlowLaneSample(Sample flowLaneSample)
+        {
+            flowLaneSamples.add(flowLaneSample);
+        }
+
+        public Sample getSequencingSample()
+        {
+            return sequencingSample;
+        }
+
+        public List<Sample> getFlowLaneSamples()
+        {
+            return flowLaneSamples;
+        }
+
+        public boolean isNewlyTracked()
+        {
+            return newlyTracked;
+        }
+    }
+
+    // data grouped by sequencing sample: <sequencing sample id, data>
+    private final Map<Long, SequencingSampleData> sequencingSampleData =
+            new HashMap<Long, SequencingSampleData>(0);
+
+    private final List<ExternalData> dataSets = new ArrayList<ExternalData>(0);
+
+    private final String recipient;
+
+    /** creates email data for given <var>recipient</var> */
+    public EntityTrackingEmailData(String recipient)
+    {
+        this.recipient = recipient;
+    }
+
+    public String getRecipient()
+    {
+        return recipient;
+    }
+
+    public Map<Long, SequencingSampleData> getSequencingSampleData()
+    {
+        return sequencingSampleData;
+    }
+
+    public List<ExternalData> getDataSets()
+    {
+        return dataSets;
+    }
+
+    /** adds info about newly tracked sequencing */
+    public void addSequencingSample(Sample sequencingSample)
+    {
+        createSequencingSampleData(sequencingSample, true);
+    }
+
+    /** adds info about newly tracked flow lane sample */
+    public void addFlowLaneSample(Sample flowLaneSample)
+    {
+        // if data about sequencing sample is not yet added add it too
+        final Sample sequencingSample = flowLaneSample.getGeneratedFrom();
+        assert sequencingSample != null;
+
+        SequencingSampleData infoOrNull = sequencingSampleData.get(sequencingSample.getId());
+        if (infoOrNull == null)
+        {
+            // because sequencing samples are processed before flow lane samples
+            // the sequencing sample we have here must have existed before
+            infoOrNull = createSequencingSampleData(sequencingSample, false);
+        }
+
+        infoOrNull.addFlowLaneSample(flowLaneSample);
+    }
+
+    private SequencingSampleData createSequencingSampleData(Sample sequencingSample,
+            boolean newlyTracked)
+    {
+        final SequencingSampleData data = new SequencingSampleData(sequencingSample, newlyTracked);
+        sequencingSampleData.put(sequencingSample.getId(), data);
+        return data;
+    }
+
+    /** adds info about newly tracked data set */
+    public void addDataSet(ExternalData dataSet)
+    {
+        dataSets.add(dataSet);
+    }
+
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/EntityTrackingEmailDataManager.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/EntityTrackingEmailDataManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff73841dba6309380a3a420704500a2bda00a8a2
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/EntityTrackingEmailDataManager.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+
+/**
+ * Manager that groups data about tracked entities into {@link EntityTrackingEmailData} objects.
+ * 
+ * @author Piotr Buczek
+ */
+class EntityTrackingEmailDataManager
+{
+    private final static String CONTACT_PERSON_EMAIL = "CONTACT_PERSON_EMAIL";
+
+    private final static String PRINCIPAL_INVESTIGATOR_EMAIL = "PRINCIPAL_INVESTIGATOR_EMAIL";
+
+    public static Collection<EntityTrackingEmailData> groupByRecipient(
+            TrackedEntities trackedEntities)
+    {
+        // <recipients email, email data>
+        final Map<String, EntityTrackingEmailData> dataByRecipient =
+                new HashMap<String, EntityTrackingEmailData>();
+        groupSequencingSamples(dataByRecipient, trackedEntities);
+        groupFlowLaneSamples(dataByRecipient, trackedEntities);
+        groupDataSetSamples(dataByRecipient, trackedEntities);
+        return dataByRecipient.values();
+    }
+
+    /** Puts tracked sequencing samples grouped by recipient into <var>result</var>. */
+    private static void groupSequencingSamples(Map<String, EntityTrackingEmailData> result,
+            TrackedEntities trackedEntities)
+    {
+        for (Sample sequencingSample : trackedEntities.getSequencingSamples())
+        {
+            for (String recipient : getFlowLaneSampleTrackingRecipients(sequencingSample))
+            {
+                final EntityTrackingEmailData emailData =
+                        getOrCreateRecipientEmailData(result, recipient);
+                emailData.addSequencingSample(sequencingSample);
+            }
+        }
+    }
+
+    /** Puts tracked flow lane samples grouped by recipient into <var>result</var>. */
+    private static void groupFlowLaneSamples(Map<String, EntityTrackingEmailData> result,
+            TrackedEntities trackedEntities)
+    {
+        for (Sample flowLaneSample : trackedEntities.getFlowLaneSamples())
+        {
+            for (String recipient : getFlowLaneSampleTrackingRecipients(flowLaneSample))
+            {
+                final EntityTrackingEmailData emailData =
+                        getOrCreateRecipientEmailData(result, recipient);
+                emailData.addFlowLaneSample(flowLaneSample);
+            }
+        }
+    }
+
+    /** Puts tracked data sets grouped by recipient into <var>result</var>. */
+    private static void groupDataSetSamples(Map<String, EntityTrackingEmailData> result,
+            TrackedEntities trackedEntities)
+    {
+        for (ExternalData dataSet : trackedEntities.getDataSets())
+        {
+            for (String recipient : getDataSetTrackingRecipients(dataSet))
+            {
+                final EntityTrackingEmailData emailData =
+                        getOrCreateRecipientEmailData(result, recipient);
+                emailData.addDataSet(dataSet);
+            }
+        }
+    }
+
+    private static EntityTrackingEmailData getOrCreateRecipientEmailData(
+            Map<String, EntityTrackingEmailData> dataByRecipient, String recipient)
+    {
+        EntityTrackingEmailData emailDataOrNull = dataByRecipient.get(recipient);
+        if (emailDataOrNull == null)
+        {
+            emailDataOrNull = new EntityTrackingEmailData(recipient);
+        }
+        return emailDataOrNull;
+    }
+
+    /**
+     * Returns an array of emails of recipient that should get a tracking information about given
+     * <var>sequencingSample</var>.
+     */
+    private static String[] getSequencingSampleTrackingRecipients(Sample sequencingSample)
+    {
+        // Recipients are taken from properties of the sequencing sample.
+        assert sequencingSample != null;
+
+        final Set<String> recipientPropertyTypeCodes = new HashSet<String>();
+        recipientPropertyTypeCodes.add(CONTACT_PERSON_EMAIL);
+        recipientPropertyTypeCodes.add(PRINCIPAL_INVESTIGATOR_EMAIL);
+
+        final List<String> recipients = new ArrayList<String>();
+        for (IEntityProperty property : sequencingSample.getProperties())
+        {
+            if (recipientPropertyTypeCodes.contains(property.getPropertyType().getCode()))
+            {
+                recipients.add(property.getValue());
+            }
+        }
+
+        // TODO 2009-11-23, Piotr Buczek: add affiliation email
+
+        return recipients.toArray(new String[0]);
+    }
+
+    /**
+     * Returns an array of emails of recipient that should get a tracking information about given
+     * <var>flowLaneSample</var>.
+     */
+    private static String[] getFlowLaneSampleTrackingRecipients(Sample flowLaneSample)
+    {
+        // Recipients are taken from properties of sequencing sample
+        // that is a parent of the flow lane sample.
+        assert flowLaneSample != null;
+        return getSequencingSampleTrackingRecipients(flowLaneSample.getGeneratedFrom());
+    }
+
+    /**
+     * Returns an array of emails of recipient that should get a tracking information about given
+     * <var>dataSet</var>.
+     */
+    private static String[] getDataSetTrackingRecipients(ExternalData dataSet)
+    {
+        // Recipients are taken from properties of sequencing sample
+        // that is a parent of a flow lane sample connected directly with the data set.
+        assert dataSet != null;
+        return getFlowLaneSampleTrackingRecipients(dataSet.getSample());
+    }
+
+}
\ No newline at end of file
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/FlowLaneTrackingEmailGenerator.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/FlowLaneTrackingEmailGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b3f05001619d61cc234e1498dd1595895d4616c
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/FlowLaneTrackingEmailGenerator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author Piotr Buczek
+ */
+public class FlowLaneTrackingEmailGenerator implements IFlowLaneTrackingEmailGenerator
+{
+
+    public List<Email> generateEmails(TrackedEntities trackedEntities)
+    {
+        final Collection<EntityTrackingEmailData> emailDataGroupedByRecipient =
+                EntityTrackingEmailDataManager.groupByRecipient(trackedEntities);
+
+        final List<Email> results = new ArrayList<Email>();
+        for (EntityTrackingEmailData emailData : emailDataGroupedByRecipient)
+        {
+            results.add(createEmail(emailData));
+        }
+
+        return results;
+    }
+
+    private Email createEmail(EntityTrackingEmailData emailData)
+    {
+        // TODO 2009-11-23, Piotr Buczek: implement
+        return null;
+    }
+
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/IFlowLaneTrackingEmailGenerator.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/IFlowLaneTrackingEmailGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..b537b8706e10fe60b508a50817c12883e6bd19e7
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/IFlowLaneTrackingEmailGenerator.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking;
+
+import java.util.List;
+
+/**
+ * @author Piotr Buczek
+ */
+interface IFlowLaneTrackingEmailGenerator
+{
+    /**
+     * Generates all {@link Email}s to be send containing information about
+     * <var>trackedEntities</var>.
+     * 
+     * @param trackedEntities recently tracked entities
+     */
+    List<Email> generateEmails(TrackedEntities trackedEntities);
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/TrackedEntities.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/TrackedEntities.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5b9fcac7ac2fb7b8a99cdf7f61856fb57f3ce70
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/TrackedEntities.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking;
+
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+
+/**
+ * Simple encapsulation of list of entities that are tracked.
+ * 
+ * @author Piotr Buczek
+ */
+public class TrackedEntities
+{
+    private final List<Sample> sequencingSamples;
+
+    private final List<Sample> flowLaneSamples;
+
+    private final List<ExternalData> dataSets;
+
+    public TrackedEntities(List<Sample> sequencingSamples, List<Sample> flowLaneSamples,
+            List<ExternalData> dataSets)
+    {
+        this.sequencingSamples = sequencingSamples;
+        this.flowLaneSamples = flowLaneSamples;
+        this.dataSets = dataSets;
+    }
+
+    public List<Sample> getSequencingSamples()
+    {
+        return sequencingSamples;
+    }
+
+    public List<Sample> getFlowLaneSamples()
+    {
+        return flowLaneSamples;
+    }
+
+    public List<ExternalData> getDataSets()
+    {
+        return dataSets;
+    }
+}