Index: continuum-model/src/main/mdo/continuum.xml
===================================================================
--- continuum-model/src/main/mdo/continuum.xml	(revision 732838)
+++ continuum-model/src/main/mdo/continuum.xml	(working copy)
@@ -439,6 +439,12 @@
           <type>boolean</type>
           <defaultValue>false</defaultValue>
         </field>
+        <field>
+          <name>consolidateNotification</name>
+          <version>1.1.3+</version>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>        
       </fields>
       <codeSegments>
         <codeSegment>
Index: continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java
===================================================================
--- continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java	(revision 732838)
+++ continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java	(working copy)
@@ -366,4 +366,11 @@
     {
         return "true".equalsIgnoreCase( value ) || "on".equalsIgnoreCase( value ) || "yes".equalsIgnoreCase( value );
     }
+
+    public void sendMessage( String messageId, List<MessageContext> messageContexts )
+        throws NotificationException
+    {
+        // TODO Auto-generated method stub
+        
+    }
 }
Index: continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/Notifier.java
===================================================================
--- continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/Notifier.java	(revision 732838)
+++ continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/Notifier.java	(working copy)
@@ -1,5 +1,7 @@
 package org.apache.maven.continuum.notification;
 
+import java.util.List;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -29,4 +31,7 @@
 
     void sendMessage( String messageId, MessageContext context )
         throws NotificationException;
+    
+    void sendMessage( String messageId, List<MessageContext> messageContexts )
+        throws NotificationException;
 }
Index: continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java
===================================================================
--- continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java	(revision 732838)
+++ continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java	(working copy)
@@ -301,6 +301,7 @@
         {
             if ( buildDef != null )
             {
+                
                 builds = buildResultDao.getBuildResultsByBuildDefinition( project.getId(), buildDef.getId(), 0, 2 );
 
                 if ( builds.size() < 2 )
Index: continuum-notifiers/continuum-notifier-wagon/src/main/java/org/apache/maven/continuum/notification/wagon/WagonContinuumNotifier.java
===================================================================
--- continuum-notifiers/continuum-notifier-wagon/src/main/java/org/apache/maven/continuum/notification/wagon/WagonContinuumNotifier.java	(revision 732838)
+++ continuum-notifiers/continuum-notifier-wagon/src/main/java/org/apache/maven/continuum/notification/wagon/WagonContinuumNotifier.java	(working copy)
@@ -390,4 +390,11 @@
                                             server.getPrivateKey(), server.getPassphrase() );
         return wagonManager.getAuthenticationInfo( repositoryId );
     }
+
+    public void sendMessage( String messageId, List<MessageContext> messageContexts )
+        throws NotificationException
+    {
+        // TODO Auto-generated method stub
+        
+    }
 }
Index: continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java
===================================================================
--- continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java	(revision 732838)
+++ continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java	(working copy)
@@ -531,4 +531,11 @@
             }
         }
     }
+
+    public void sendMessage( String messageId, List<MessageContext> messageContexts )
+        throws NotificationException
+    {
+        // TODO Auto-generated method stub
+        
+    }
 }
Index: continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java
===================================================================
--- continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java	(revision 732838)
+++ continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java	(working copy)
@@ -248,4 +248,11 @@
 
         return fromPassword;
     }
+
+    public void sendMessage( String messageId, List<MessageContext> messageContexts )
+        throws NotificationException
+    {
+        // TODO Auto-generated method stub
+        
+    }
 }
Index: continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java
===================================================================
--- continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java	(revision 732838)
+++ continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java	(working copy)
@@ -80,6 +80,13 @@
      * for the build.
      */
     private boolean sendOnScmFailure;
+    
+    /**
+     * Detemines if the notifier should fire for only for every multi module project in a group.<p>
+     * <code>true</code> implies notifier executes only after every multi module project    
+     * for the build.
+     */    
+    private boolean consolidateNotification;
 
     /**
      * Detemines if the save operation returns to the project group notifier page or not.<p>
@@ -145,6 +152,8 @@
         notifier.setSendOnWarning( isSendOnWarning() );
 
         notifier.setSendOnScmFailure( isSendOnScmFailure() );
+        
+        notifier.setConsolidateNotification( isConsolidateNotification() );
 
         setNotifierConfiguration( notifier );
 
@@ -196,6 +205,8 @@
         setSendOnWarning( notifier.isSendOnWarning() );
 
         setSendOnScmFailure( notifier.isSendOnScmFailure() );
+        
+        setConsolidateNotification( notifier.isConsolidateNotification() );
 
         initConfiguration( notifier.getConfiguration() );
 
@@ -340,4 +351,14 @@
 
     protected abstract void checkAuthorization()
         throws AuthorizationRequiredException, ContinuumException;
+
+    public boolean isConsolidateNotification()
+    {
+        return consolidateNotification;
+    }
+
+    public void setConsolidateNotification( boolean consolidateNotification )
+    {
+        this.consolidateNotification = consolidateNotification;
+    }
 }
Index: continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java
===================================================================
--- continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java	(revision 732838)
+++ continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java	(working copy)
@@ -328,6 +328,14 @@
             }
             sb.append( "SCM Failure" );
         }
+        if ( notifier.isConsolidateNotification() )
+        {
+            if ( sb.length() > 0 )
+            {
+                sb.append( '/' );
+            }
+            sb.append( "Consolidated Notification" );
+        }
         ns.setEvents( sb.toString() );
 
         ns.setEnabled( notifier.isEnabled() );
Index: continuum-webapp/src/main/resources/localization/Continuum.properties
===================================================================
--- continuum-webapp/src/main/resources/localization/Continuum.properties	(revision 732838)
+++ continuum-webapp/src/main/resources/localization/Continuum.properties	(working copy)
@@ -488,6 +488,7 @@
 notifier.event.sendOnError = Send on Error
 notifier.event.sendOnWarning = Send on Warning
 notifier.event.sendOnScmFailure = Send On SCM Failure
+notifier.event.consolidateNotification = Consolidate Notification
 
 # ----------------------------------------------------------------------
 # Page: BuildResults
Index: continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp
===================================================================
--- continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp	(revision 732838)
+++ continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp	(working copy)
@@ -60,6 +60,7 @@
                 <s:checkbox label="%{getText('notifier.event.sendOnWarning')}" name="sendOnWarning" value="sendOnWarning" fieldValue="true"/>
                 <s:checkbox label="%{getText('notifier.event.sendOnScmFailure')}" name="sendOnScmFailure" value="sendOnScmFailure" fieldValue="true"/>
                 <s:checkbox label="%{getText('notifier.event.sendOnScmFailure')}" name="sendOnScmFailure" value="sendOnScmFailure" fieldValue="true"/>
+                <s:checkbox label="%{getText('notifier.event.consolidateNotification')}" name="consolidateNotification" value="consolidateNotification" fieldValue="true"/>
               </tbody>
             </table>
             <div class="functnbar3">
Index: continuum-core/src/test/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifierTest.java
===================================================================
--- continuum-core/src/test/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifierTest.java	(revision 732838)
+++ continuum-core/src/test/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifierTest.java	(working copy)
@@ -31,6 +31,7 @@
 
 import org.apache.continuum.notification.mail.MockJavaMailSender;
 import org.apache.maven.continuum.AbstractContinuumTest;
+import org.apache.maven.continuum.execution.ContinuumBuildExecutorConstants;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
 import org.apache.maven.continuum.model.project.ProjectGroup;
@@ -72,7 +73,34 @@
 
         dumpContent( mailMessage, "recipient@host.com" );
     }
+    
+    public void testConsolidatedSuccesfulBUild()
+        throws Exception
+    {
+        MailContinuumNotifier notifier = (MailContinuumNotifier) lookup( Notifier.class.getName(), "mail" );
+        String toOverride = "recipient@host.com";
+        notifier.setToOverride( toOverride );
 
+
+        List<Project> projects = new ArrayList<Project>();
+        
+        //TODO: figure out the jpox "detach" error and add more test projects 
+        ProjectGroup group = createStubProjectGroup( "foo.bar", "" );
+        Project project0 = addProject( "Test Project-0", group );
+
+        projects.add( project0 );
+
+        List<BuildResult> buildResults = new ArrayList<BuildResult>();
+        buildResults.add( makeBuild( ContinuumProjectState.OK ) );
+        
+        MimeMessage mailMessage = sendNotificationAndGetMessage( projects, buildResults, "lots out build output", toOverride );
+
+       assertEquals( "[continuum] BUILD [SUCCESS]: [foo.bar - Test Project-0]", mailMessage.getSubject() );
+
+       dumpContent( mailMessage, "recipient@host.com" );
+
+    }
+    
     public void testFailedBuild()
         throws Exception
     {
@@ -200,7 +228,78 @@
 
         return mailMessage;
     }
+    
+    private MimeMessage sendNotificationAndGetMessage( List<Project> projects, List<BuildResult> builds, String buildOutput,
+                                                       String toOverride )
+        throws Exception
+    {
+        
+        List<MessageContext> contexts = new ArrayList<MessageContext>();
+        
+        for ( int i = 0; i < projects.size(); i++ )
+        {
+            //init
+            MessageContext context = new MessageContext();
+            ProjectNotifier projectNotifier = new ProjectNotifier();
+            projectNotifier.setType( "mail" );
+            Map<String, String> config = new HashMap<String, String>();
+            config.put( MailContinuumNotifier.ADDRESS_FIELD, "foo@bar" );
+            projectNotifier.setConfiguration( config );
+            List<ProjectNotifier> projectNotifiers = new ArrayList<ProjectNotifier>();
+            projectNotifiers.add( projectNotifier );
+            context.setNotifier( projectNotifiers );
+            
+            //----------------------------------
+            // consolidated projects and results
+            //----------------------------------
+            context.setProject( projects.get( i ) );
+            context.setBuildResult( builds.get( i ) );
+            contexts.add( context );
 
+        }
+
+        // context.put( ContinuumNotificationDispatcher.CONTEXT_BUILD_OUTPUT, buildOutput );
+
+        // context.put( "buildHost", "foo.bar.com" );
+
+        // ----------------------------------------------------------------------
+        //
+        // ----------------------------------------------------------------------
+
+        Notifier notifier = (Notifier) lookup( Notifier.class.getName(), "mail" );
+
+        ( (MailContinuumNotifier) notifier ).setBuildHost( "foo.bar.com" );
+        
+        notifier.sendMessage( ContinuumNotificationDispatcher.MESSAGE_ID_BUILD_COMPLETE, contexts );
+        // ----------------------------------------------------------------------
+        //
+        // ----------------------------------------------------------------------
+
+        MockJavaMailSender mailSender = (MockJavaMailSender) lookup( JavaMailSender.class, "continuum" );
+
+        assertEquals( 1, mailSender.getReceivedEmails().size() );
+
+        List<MimeMessage> mails = mailSender.getReceivedEmails();
+
+        MimeMessage mailMessage = (MimeMessage) mails.get( 0 );
+
+        // ----------------------------------------------------------------------
+        //
+        // ----------------------------------------------------------------------
+
+        assertEquals( "continuum@localhost", ( (InternetAddress) mailMessage.getFrom()[0] ).getAddress() );
+
+        assertEquals( "Continuum", ( (InternetAddress) mailMessage.getFrom()[0] ).getPersonal() );
+
+        Address[] tos = mailMessage.getRecipients( RecipientType.TO );
+
+        assertEquals( 1, tos.length );
+
+        assertEquals( toOverride == null ? "foo@bar" : toOverride, ( (InternetAddress) tos[0] ).getAddress() );
+
+        return mailMessage;
+    }
+
     private BuildResult makeBuild( int state )
     {
         BuildResult build = new BuildResult();
Index: continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java
===================================================================
--- continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java	(revision 732838)
+++ continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java	(working copy)
@@ -114,7 +114,7 @@
     private PlexusContainer container;
 
     private LocalRepository repository;
-    
+
     // ----------------------------------------------------------------------
     // MavenBuilderHelper Implementation
     // ----------------------------------------------------------------------
@@ -216,7 +216,7 @@
         {
             List<ProjectDeveloper> developers = new ArrayList<ProjectDeveloper>();
 
-            for ( Developer d : (List<Developer>)mavenProject.getDevelopers() )
+            for ( Developer d : (List<Developer>) mavenProject.getDevelopers() )
             {
                 ProjectDeveloper cd = new ProjectDeveloper();
 
@@ -257,7 +257,7 @@
 
         List<ProjectDependency> dependencies = new ArrayList<ProjectDependency>();
 
-        for ( Dependency dependency : (List<Dependency>)mavenProject.getDependencies() )
+        for ( Dependency dependency : (List<Dependency>) mavenProject.getDependencies() )
         {
             ProjectDependency cd = new ProjectDependency();
 
@@ -270,7 +270,7 @@
             dependencies.add( cd );
         }
 
-        for ( Plugin dependency : (List<Plugin>)mavenProject.getBuildPlugins() )
+        for ( Plugin dependency : (List<Plugin>) mavenProject.getBuildPlugins() )
         {
             ProjectDependency cd = new ProjectDependency();
 
@@ -283,7 +283,7 @@
             dependencies.add( cd );
         }
 
-        for ( ReportPlugin dependency : (List<ReportPlugin>)mavenProject.getReportPlugins() )
+        for ( ReportPlugin dependency : (List<ReportPlugin>) mavenProject.getReportPlugins() )
         {
             ProjectDependency cd = new ProjectDependency();
 
@@ -296,7 +296,7 @@
             dependencies.add( cd );
         }
 
-        for ( Extension dependency : (List<Extension>)mavenProject.getBuildExtensions() )
+        for ( Extension dependency : (List<Extension>) mavenProject.getBuildExtensions() )
         {
             ProjectDependency cd = new ProjectDependency();
 
@@ -347,6 +347,8 @@
 
                     userNotifier.setSendOnScmFailure( notifier.isSendOnScmFailure() );
 
+                    userNotifier.setConsolidateNotification( notifier.isConsolidateNotification() );
+
                     userNotifiers.add( userNotifier );
                 }
             }
@@ -370,8 +372,8 @@
 
         try
         {
-            //   TODO: This seems like code that is shared with DefaultMaven, so it should be moved to the project
-            //   builder perhaps
+            // TODO: This seems like code that is shared with DefaultMaven, so it should be moved to the project
+            // builder perhaps
 
             Settings settings = getSettings();
 
@@ -477,7 +479,8 @@
             result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_SCM_CONNECTION, getProjectName( project ) );
 
             log.error(
-                "Missing 'connection' element in the 'scm' element in the " + getProjectName( project ) + " POM." );
+                               "Missing 'connection' element in the 'scm' element in the " + getProjectName( project )
+                                   + " POM." );
 
             return null;
         }
@@ -513,13 +516,13 @@
     }
 
     private List<ProjectNotifier> getNotifiers( ContinuumProjectBuildingResult result, MavenProject mavenProject,
-                               Project continuumProject )
+                                                Project continuumProject )
     {
         List<ProjectNotifier> notifiers = new ArrayList<ProjectNotifier>();
 
         if ( mavenProject.getCiManagement() != null && mavenProject.getCiManagement().getNotifiers() != null )
         {
-            for ( Notifier projectNotifier : (List<Notifier>)mavenProject.getCiManagement().getNotifiers() )
+            for ( Notifier projectNotifier : (List<Notifier>) mavenProject.getCiManagement().getNotifiers() )
             {
                 ProjectNotifier notifier = new ProjectNotifier();
 
@@ -548,6 +551,8 @@
                 notifier.setSendOnError( projectNotifier.isSendOnError() );
 
                 notifier.setSendOnWarning( projectNotifier.isSendOnWarning() );
+                
+                notifier.setConsolidateNotification( false );
 
                 notifier.setSendOnScmFailure( false );
 
@@ -596,11 +601,8 @@
 
         if ( repository != null )
         {
-            return artifactRepositoryFactory.createArtifactRepository( repository.getName(), 
-                                                                       "file://" + repository.getLocation(), 
-                                                                       repositoryLayout,
-                                                                       null, 
-                                                                       null );
+            return artifactRepositoryFactory.createArtifactRepository( repository.getName(), "file://"
+                + repository.getLocation(), repositoryLayout, null, null );
         }
         else if ( !( StringUtils.isEmpty( settings.getLocalRepository() ) ) )
         {
@@ -692,8 +694,8 @@
 
             for ( Profile profile : profiles )
             {
-                message.append( "\n - " ).append( profile.getId() ).append( " (source: " )
-                    .append( profile.getSource() ).append( ")" );
+                message.append( "\n - " ).append( profile.getId() ).append( " (source: " ).append( profile.getSource() ).append(
+                                                                                                                                 ")" );
             }
 
         }
@@ -705,10 +707,8 @@
     }
 
     /**
-     * @todo [BP] this might not be required if there is a better way to pass
-     * them in. It doesn't feel quite right.
-     * @todo [JC] we should at least provide a mapping of protocol-to-proxy for
-     * the wagons, shouldn't we?
+     * @todo [BP] this might not be required if there is a better way to pass them in. It doesn't feel quite right.
+     * @todo [JC] we should at least provide a mapping of protocol-to-proxy for the wagons, shouldn't we?
      */
     private void resolveParameters( Settings settings )
         throws ComponentLookupException, ComponentLifecycleException, SettingsConfigurationException
@@ -783,7 +783,7 @@
             throw new InitializationException( "Can't initialize '" + getClass().getName() + "'", e );
         }
     }
-    
+
     public void setLocalRepository( LocalRepository repository )
     {
         this.repository = repository;
Index: continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java
===================================================================
--- continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java	(revision 732838)
+++ continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java	(working copy)
@@ -19,6 +19,8 @@
  * under the License.
  */
 
+import java.util.List;
+
 import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
@@ -181,4 +183,11 @@
             }
         }
     }
+
+    public void sendMessage( String messageId, List<MessageContext> messageContexts )
+        throws NotificationException
+    {
+        // TODO Auto-generated method stub
+        
+    }
 }
Index: continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java
===================================================================
--- continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java	(revision 732838)
+++ continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java	(working copy)
@@ -41,6 +41,7 @@
 import org.apache.maven.continuum.notification.AbstractContinuumNotifier;
 import org.apache.maven.continuum.notification.ContinuumNotificationDispatcher;
 import org.apache.maven.continuum.notification.MessageContext;
+import org.apache.maven.continuum.notification.MessageIdMessageContext;
 import org.apache.maven.continuum.notification.NotificationException;
 import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.apache.maven.continuum.reports.surefire.ReportTestResult;
@@ -68,6 +69,7 @@
 import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -78,6 +80,7 @@
 public class MailContinuumNotifier
     extends AbstractContinuumNotifier
     implements Initializable
+    
 {
     private Logger log = LoggerFactory.getLogger( getClass() );
 
@@ -152,6 +155,8 @@
      * @plexus.configuration
      */
     private boolean includeOutput = false;
+    
+    public static final String NEWLINE = System.getProperty("line.separator");
 
     /**
      * Customizable mail subject.  Use any combination of literal text, project or build attributes.
@@ -240,7 +245,240 @@
     {
         return "mail";
     }
+    
 
+    public void sendMessage(String messageId, List<MessageContext> messageContexts )
+        throws NotificationException
+    {
+       
+        
+        List<Project> projects = new ArrayList<Project>();
+        List<BuildResult> builds = new ArrayList<BuildResult>();
+        List<String> buildOutputs = new ArrayList<String>();
+        List<BuildDefinition> buildDefinitions = new ArrayList<BuildDefinition>();
+        List<ProjectScmRoot> projectScmRoots = new ArrayList<ProjectScmRoot>();
+        Map<Integer, List<ProjectNotifier>> projectIdProjectNotifiersMap = new HashMap<Integer, List<ProjectNotifier>>();
+        
+        
+        for ( MessageContext context : messageContexts )
+        {            
+            
+            
+            Project project = context.getProject();
+            List<ProjectNotifier> notifiers = context.getNotifiers();
+            BuildResult build = context.getBuildResult();
+            String buildOutput = getBuildOutput( project, build );
+            BuildDefinition buildDefinition = context.getBuildDefinition();
+            ProjectScmRoot projectScmRoot = context.getProjectScmRoot();
+            
+            boolean isPrepareBuildComplete =
+                messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_PREPARE_BUILD_COMPLETE );
+            
+            if ( projectScmRoot == null && isPrepareBuildComplete )
+            {
+                continue;
+            }
+            
+            // ----------------------------------------------------------------------
+            // If there wasn't any building done, don't notify
+            // ----------------------------------------------------------------------
+
+            if ( build == null && !isPrepareBuildComplete )
+            {
+                continue;
+            }
+
+            projects.add( project );
+            builds.add( build );
+            buildOutputs.add( buildOutput );
+            buildDefinitions.add( buildDefinition );
+            projectScmRoots.add( projectScmRoot );
+            projectIdProjectNotifiersMap.put( new Integer( project.getId() ), notifiers );
+            
+        }
+        // ----------------------------------------------------------------------
+        // Generate and send email
+        // ----------------------------------------------------------------------
+        
+        if ( messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_BUILD_COMPLETE ) )
+        {
+            buildComplete( projects, projectIdProjectNotifiersMap, builds, buildOutputs, messageId, messageContexts,  buildDefinitions );
+        }
+        
+    }
+    
+
+    private void buildComplete( List<Project> projects,  Map<Integer, List<ProjectNotifier>> projectIdProjectNotifiersMap, List<BuildResult> builds, List<String> buildOutputs,
+                                String messageId, List<MessageContext> messageContexts, List<BuildDefinition> buildDefinitions )
+        throws NotificationException
+    {
+        Iterator<Project> iterator = projects.iterator();
+                
+        List<ProjectNotifier> finalNotifiersList = new ArrayList<ProjectNotifier>();
+        List<BuildResult> previousBuilds = new ArrayList<BuildResult>();
+        
+        int i =0;
+        while(iterator.hasNext())
+        {
+          Project p =    iterator.next();
+          BuildDefinition bd =  buildDefinitions.get( i );
+          BuildResult build = builds.get( i );
+          
+          BuildResult previousBuild = getPreviousBuild( p, bd, build );
+          previousBuilds.add( previousBuild );
+          
+          List<ProjectNotifier> notifiers = projectIdProjectNotifiersMap.get( new Integer(p.getId()) );
+          
+          // ----------------------------------------------------------------------
+          // Check if the mail should be sent at all
+          // ----------------------------------------------------------------------          
+          for ( ProjectNotifier notifier : notifiers )
+            {
+                if ( shouldNotify( build, previousBuild, notifier ) && !finalNotifiersList.contains( notifier ) )
+                {
+                    finalNotifiersList.add( notifier );
+                }
+            }
+          
+          i++;                  
+        }
+
+        buildComplete( projects, finalNotifiersList, builds, previousBuilds, buildOutputs, messageId, messageContexts, buildDefinitions );
+    }    
+    
+    private void buildComplete( List<Project> projects, List<ProjectNotifier> notifiers, List<BuildResult> builds,
+                                List<BuildResult> previousBuilds, List<String> buildOutputs, String messageId,
+                                List<MessageContext> messageContexts, List<BuildDefinition> buildDefinitions )
+        throws NotificationException
+    {
+        // ----------------------------------------------------------------------
+        // Generate the mail contents
+        // ----------------------------------------------------------------------
+
+        String packageName = getClass().getPackage().getName().replace( '.', '/' );       
+
+        StringWriter writer = null;
+
+        String content = "";
+        
+        int i=0;
+        for (Project project: projects)
+        {
+            String templateName = packageName + "/templates/" + project.getExecutorId() + "/" + messageId + ".vm";
+            writer = new StringWriter();
+            BuildResult build = builds.get( i );
+            BuildResult previousBuild = previousBuilds.get( i );
+            BuildDefinition buildDefinition = buildDefinitions.get( i );
+
+            try
+            {
+                VelocityContext context = new VelocityContext();
+
+                context.put( "includeTestSummary", includeTestSummary );
+
+                context.put( "includeOutput", includeOutput );
+
+                if ( includeBuildResult )
+                {
+                    context.put( "buildOutput", buildOutputs.get( i ) );
+                }
+
+                if ( includeBuildSummary )
+                {
+                    context.put( "build", build );
+
+                    ReportTestResult reportTestResult =
+                        reportTestSuiteGenerator.generateReportTestResult( build.getId(), project.getId() );
+
+                    context.put( "testResult", reportTestResult );
+
+                    context.put( "project", project );
+
+                    context.put( "changesSinceLastUpdate", continuum.getChangesSinceLastUpdate( project.getId() ) );
+
+                    context.put( "previousBuild", previousBuild );
+
+                    // ----------------------------------------------------------------------
+                    // Tools
+                    // ----------------------------------------------------------------------
+
+                    context.put( "formatter", formatterTool );
+
+                    // TODO: Make the build host a part of the build
+
+                    context.put( "buildHost", buildHost );
+
+                    String osName = System.getProperty( "os.name" );
+
+                    String osPatchLevel = System.getProperty( "sun.os.patch.level" );
+
+                    if ( osPatchLevel != null )
+                    {
+                        osName = osName + "(" + osPatchLevel + ")";
+                    }
+
+                    context.put( "osName", osName );
+
+                    context.put( "javaVersion", System.getProperty( "java.version" ) + "("
+                        + System.getProperty( "java.vendor" ) + ")" );
+
+                    // TODO only in case of a java project ?
+                    context.put( "javaHomeInformations", getJavaHomeInformations( buildDefinition ) );
+
+                    context.put( "builderVersions", getBuilderVersion( buildDefinition, project ) );
+                }
+
+                // ----------------------------------------------------------------------
+                // Data objects
+                // ----------------------------------------------------------------------
+
+                context.put( "reportUrl", getReportUrl( project, build, configurationService ) );
+
+                // TODO put other profile env var could be a security if they provide passwords ?
+
+                // ----------------------------------------------------------------------
+                // Generate
+                // ----------------------------------------------------------------------
+
+                velocity.getEngine().mergeTemplate( templateName, context, writer );
+
+                content  += writer.getBuffer().toString();
+                
+                content += StringUtils.repeat( NEWLINE, 5 );
+                
+            }
+            catch ( ResourceNotFoundException e )
+            {
+                log.info( "No such template: '" + templateName + "'." );
+
+                return;
+            }
+            catch ( Exception e )
+            {
+                throw new NotificationException( "Error while generating mail contents.", e );
+            }
+
+        }//end for
+        
+        // ----------------------------------------------------------------------
+        // Send the mail
+        // ----------------------------------------------------------------------
+
+        String subject;
+        try
+        {
+            subject = generateSubject( projects, builds );
+        }
+        catch ( Exception e )
+        {
+            throw new NotificationException( "Error while generating mail subject.", e );
+        }
+        
+        sendMessage( projects.get( 0 ), notifiers, subject, content, messageContexts );
+    }
+
+    
+    // -------------------------------------------------------------------------------------------
     public void sendMessage( String messageId, MessageContext context )
         throws NotificationException
     {
@@ -275,6 +513,7 @@
         if ( messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_BUILD_COMPLETE ) )
         {
             buildComplete( project, notifiers, build, buildOutput, messageId, context, buildDefinition );
+            
         }
         else if ( isPrepareBuildComplete )
         {
@@ -311,7 +550,7 @@
         // ----------------------------------------------------------------------
         // Generate the mail contents
         // ----------------------------------------------------------------------
-
+        
         String packageName = getClass().getPackage().getName().replace( '.', '/' );
 
         String templateName = packageName + "/templates/" + project.getExecutorId() + "/" + messageId + ".vm";
@@ -336,10 +575,11 @@
             if ( includeBuildSummary )
             {
                 context.put( "build", build );
-
+                
+                
                 ReportTestResult reportTestResult =
                     reportTestSuiteGenerator.generateReportTestResult( build.getId(), project.getId() );
-
+                
                 context.put( "testResult", reportTestResult );
 
                 context.put( "project", project );
@@ -418,8 +658,11 @@
         {
             throw new NotificationException( "Error while generating mail subject.", e );
         }
-
-        sendMessage( project, notifiers, subject, content, messageContext );
+        
+        List<MessageContext> messageContextList = new ArrayList<MessageContext>();
+        messageContextList.add( messageContext );
+         
+        sendMessage( project, notifiers, subject, content, messageContextList );
     }
 
     private void prepareBuildComplete( ProjectScmRoot projectScmRoot, List<ProjectNotifier> notifiers, 
@@ -573,6 +816,26 @@
         return writer.toString();
     }
     
+
+    private String generateSubject(List <Project> projects,List <BuildResult> builds )
+        throws Exception
+    {
+        String state = getState( projects, builds );
+        String projectsString = getProjectsToSubject( projects );
+        //${project.groupId} ${project.name}
+        subjectFormat = "[continuum] BUILD [${state}]: [${projects}]";
+        
+        VelocityContext context = new VelocityContext();
+        context.put( "projects", projectsString );
+        context.put( "state", state );
+
+        StringWriter writer = new StringWriter();
+
+        boolean velocityResults = velocity.getEngine().evaluate( context, writer, "subjectPattern", subjectFormat );
+
+        return writer.toString();
+    }    
+    
     private String generateSubject( ProjectScmRoot projectScmRoot )
         throws Exception
     {
@@ -619,6 +882,87 @@
         }
     }
     
+    private String getState( List<Project> projects, List<BuildResult> builds )
+    {
+        int i = 0;
+        List<String> result = new ArrayList<String>();
+        
+        for ( Project project : projects )
+        {
+            BuildResult build = builds.get( i );                        
+            
+            int state = project.getState();
+
+            if ( build != null )
+            {
+                state = build.getState();
+            }
+
+            if ( state == ContinuumProjectState.OK )
+            {
+                if (!result.contains("SUCCESS"))
+                {
+                    result.add( "SUCCESS" );
+                }
+            }
+            else if ( state == ContinuumProjectState.FAILED )
+            {
+                if (!result.contains("FAILURE"))
+                {
+                    result.add( "FAILURE" );
+                }
+            }
+            else if ( state == ContinuumProjectState.ERROR )
+            {
+                if (!result.contains("ERROR"))
+                {
+                    result.add( "ERROR" );
+                }
+            }
+            else
+            {
+                log.warn( "Unknown build state " + state + " for project " + project.getId() );
+
+                result.add( "ERROR: Unknown build state " + state ) ;
+            }            
+            
+            i++;
+        }
+        String toResult = "";
+        for ( String r : result )
+        {
+            toResult  += toResult.length()==0? r : ", " + r;
+        }
+        
+        return toResult;
+    }
+    
+    private String getProjectsToSubject( List<Project> projects)
+    {
+        String result = "";
+        
+        for ( Project project : projects )
+        {
+            if (result.length() == 0)
+            {
+                result += project.getGroupId() + " - " + project.getName();
+            }
+            else
+            {
+                result +=", " + project.getGroupId() + " - " + project.getName();
+            }
+            
+            //don't display all projects in the subject
+            if (result.length() >= 200)
+            {
+                result +=", ...";
+                break;
+            }
+        }
+        return result;
+    }    
+    
+    
     private String getState( ProjectScmRoot projectScmRoot )
     {
         int state = projectScmRoot.getState();
@@ -641,7 +985,7 @@
     }
     
     private void sendMessage( Project project, List<ProjectNotifier> notifiers, String subject, String content,
-                              MessageContext context )
+                              List<MessageContext> contexts )
         throws NotificationException
     {
         if ( notifiers.size() == 0 )
@@ -658,9 +1002,8 @@
 
         if ( fromMailbox == null )
         {
-            log
-                .warn( project.getName() +
-                    ": Project is missing nag email and global from mailbox is missing, not sending mail." );
+            log.warn( project.getName()
+                + ": Project is missing nag email and global from mailbox is missing, not sending mail." );
 
             return;
         }
@@ -708,49 +1051,57 @@
                                 log.info( "Recipient: To '" + to + "'." );
                                 message.addRecipient( Message.RecipientType.TO, to );
                             }
-                            
+
                         }
 
                         String committerField = (String) notifier.getConfiguration().get( COMMITTER_FIELD );
-                        if ( StringUtils.isNotEmpty( committerField ) && context.getBuildResult() != null )
+                        if ( StringUtils.isNotEmpty( committerField ) )// && context.getBuildResult() != null )
+
                         {
-                            if ( Boolean.parseBoolean( committerField ) )
+                            for ( MessageContext context : contexts )
                             {
-                                ScmResult scmResult = context.getProject().getScmResult();
-                                if ( scmResult != null && scmResult.getChanges() != null &&
-                                    !scmResult.getChanges().isEmpty() )
+                                if ( context.getBuildResult() != null )
                                 {
-                                    List<ProjectDeveloper> developers = project.getDevelopers();
-                                    if ( developers == null || developers.isEmpty() )
+                                    if ( Boolean.parseBoolean( committerField ) )
                                     {
-                                        log.warn( "No developers have been configured...notifcation email " +
-                                            "will not be sent" );
-                                        return;
-                                    }
+                                        ScmResult scmResult = context.getProject().getScmResult();
+                                        if ( scmResult != null && scmResult.getChanges() != null
+                                            && !scmResult.getChanges().isEmpty() )
+                                        {
+                                            List<ProjectDeveloper> developers = context.getProject().getDevelopers();
+                                            if ( developers == null || developers.isEmpty() )
+                                            {
+                                                log.warn( "No developers have been configured...notifcation email "
+                                                    + "will not be sent" );
+                                                return;
+                                            }
 
-                                    Map<String, String> developerToEmailMap = mapDevelopersToRecipients( developers );
+                                            Map<String, String> developerToEmailMap =
+                                                mapDevelopersToRecipients( developers );
 
-                                    List<ChangeSet> changes = scmResult.getChanges();
+                                            List<ChangeSet> changes = scmResult.getChanges();
 
-                                    for ( ChangeSet changeSet : changes )
-                                    {
-                                        String scmId = changeSet.getAuthor();
-                                        if ( StringUtils.isNotEmpty( scmId ) )
-                                        {
-                                            String email = developerToEmailMap.get( scmId );
-                                            if ( StringUtils.isEmpty( email ) )
+                                            for ( ChangeSet changeSet : changes )
                                             {
-                                                //TODO: Add a default domain so mail address won't be required
-                                                log.warn( "no email address is defined in developers list for '" +
-                                                    scmId + "' scm id." );
-                                            }
-                                            else
-                                            {
-                                                // TODO: set a proper name
-                                                InternetAddress to = new InternetAddress( email.trim() );
-                                                log.info( "Recipient: To '" + to + "'." );
+                                                String scmId = changeSet.getAuthor();
+                                                if ( StringUtils.isNotEmpty( scmId ) )
+                                                {
+                                                    String email = developerToEmailMap.get( scmId );
+                                                    if ( StringUtils.isEmpty( email ) )
+                                                    {
+                                                        // TODO: Add a default domain so mail address won't be required
+                                                        log.warn( "no email address is defined in developers list for '"
+                                                            + scmId + "' scm id." );
+                                                    }
+                                                    else
+                                                    {
+                                                        // TODO: set a proper name
+                                                        InternetAddress to = new InternetAddress( email.trim() );
+                                                        log.info( "Recipient: To '" + to + "'." );
 
-                                                message.addRecipient( Message.RecipientType.TO, to );
+                                                        message.addRecipient( Message.RecipientType.TO, to );
+                                                    }
+                                                }
                                             }
                                         }
                                     }
@@ -770,12 +1121,14 @@
                 message.addRecipient( Message.RecipientType.TO, to );
             }
 
+
             message.setSentDate( new Date() );
 
             if ( message.getAllRecipients() != null && ( (Address[]) message.getAllRecipients() ).length > 0 )
             {
                 javaMailSender.send( message );
             }
+
         }
         catch ( AddressException ex )
         {
@@ -873,13 +1226,17 @@
 
                 message.addRecipient( Message.RecipientType.TO, to );
             }
+            
+            if ( message.getAllRecipients() != null && ( (Address[]) message.getAllRecipients() ).length > 0 )
+            {
+                message.setSentDate( new Date() );
+            }
 
-            message.setSentDate( new Date() );
-
             if ( message.getAllRecipients() != null && ( (Address[]) message.getAllRecipients() ).length > 0 )
             {
                 javaMailSender.send( message );
             }
+
         }
         catch ( AddressException ex )
         {
@@ -961,4 +1318,4 @@
     {
         this.toOverride = toOverride;
     }
-}
+}
\ No newline at end of file
Index: continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java
===================================================================
--- continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java	(revision 732838)
+++ continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java	(working copy)
@@ -22,13 +22,17 @@
 import org.apache.continuum.dao.ProjectDao;
 import org.apache.continuum.dao.ProjectGroupDao;
 import org.apache.continuum.model.project.ProjectScmRoot;
+import org.apache.continuum.taskqueue.manager.TaskQueueManager;
+import org.apache.continuum.taskqueue.manager.TaskQueueManagerException;
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
+import org.apache.maven.continuum.model.project.ProjectDependency;
 import org.apache.maven.continuum.model.project.ProjectGroup;
 import org.apache.maven.continuum.model.project.ProjectNotifier;
 import org.apache.maven.continuum.notification.manager.NotifierManager;
 import org.apache.maven.continuum.store.ContinuumStoreException;
+import org.codehaus.plexus.taskqueue.TaskQueue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,6 +40,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
@@ -63,6 +68,14 @@
      */
     private ProjectGroupDao projectGroupDao;
 
+    /**
+     * @plexus.requirement
+     */
+    private TaskQueueManager taskQueueManager;
+
+    //private Map<> projectList = new ArrayList<Project>();
+    private Map<Project, Object[]> consolidatedResult = new HashMap<Project, Object[]>();
+
     // ----------------------------------------------------------------------
     // ContinuumNotificationDispatcher Implementation
     // ----------------------------------------------------------------------
@@ -94,7 +107,8 @@
 
     public void buildComplete( Project project, BuildDefinition buildDefinition, BuildResult buildResult )
     {
-        sendNotification( MESSAGE_ID_BUILD_COMPLETE, project, buildDefinition, buildResult );
+        sendNotification( MESSAGE_ID_BUILD_COMPLETE, project, buildDefinition, buildResult, false );
+        sendNotificationPerMultiModule( MESSAGE_ID_BUILD_COMPLETE, project, buildDefinition, buildResult );
     }
 
     public void prepareBuildComplete( ProjectScmRoot projectScmRoot )
@@ -102,13 +116,244 @@
         sendNotification( MESSAGE_ID_PREPARE_BUILD_COMPLETE, projectScmRoot );
     }
 
-    // ----------------------------------------------------------------------
-    //
-    // ----------------------------------------------------------------------
+    private void sendNotificationPerMultiModule( String messageId, Project project, BuildDefinition buildDefinition,
+                                                 BuildResult buildResult )
+    {
+        Object[] tuple = new Object[] { project, buildDefinition, buildResult };
+        int buildDefnIndex = 1, buildResultIndex = 2;
 
+        ProjectGroup projectGroup = null;
+        List<ProjectNotifier> consolidatedNotifiers = null;
+        
+        try
+        {
+            project = projectDao.getProjectWithAllDetails( project.getId() );
+            
+            projectGroup =
+                projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( project.getProjectGroup().getId() );
+            List<ProjectNotifier> notifiers = projectGroup.getNotifiers();
+            consolidatedNotifiers = getConsolidatedNotifiers( notifiers );
+
+            if ( consolidatedNotifiers.isEmpty() )
+            {
+                log.info( "Project group has no consolidated notifier." );
+                return;
+            }
+        }
+        catch ( ContinuumStoreException e )
+        {
+            log.error( "Error while population the notification context." );
+        }
+
+        if ( consolidatedResult.isEmpty() )
+        {
+            log.info( "adding project to consolidated notification: " + getProjectId( project ) );
+            consolidatedResult.put( project, tuple );
+        }
+        else
+        {
+            if ( isPartOfMultiModule( consolidatedResult, project ) )
+            {
+                log.info( "adding member project to consolidated notification: " + getProjectId( project ) );
+
+                consolidatedResult.put( project, tuple );
+            }
+            else
+            {
+                // send the consolidated notification, empty the list, and add the new project to list
+                log.info( "not part of multi module, sending the consolidated notification" );
+
+                sendNotificationPerMultiModule( messageId, buildDefnIndex, buildResultIndex, consolidatedNotifiers );
+
+                consolidatedResult.clear();
+
+                consolidatedResult.put( project, tuple );
+            }
+        }
+
+        //send  all the remaining notifications  : if no more projects in build queue OR building a project with different project group.
+        try
+        {
+            int currentId = taskQueueManager.getCurrentProjectIdBuilding();
+            Project currentProject = projectDao.getProjectWithAllDetails( currentId );
+            
+            boolean empty = taskQueueManager.getProjectsInBuildQueue().isEmpty();
+            
+
+            if (! empty)
+            {
+                log.info( "projects in build queue..........." );
+            }
+            
+            if ( empty  || ( currentId != -1 && currentProject.getProjectGroup().getId() != project.getProjectGroup().getId()  ) )
+            {
+                
+                log.info( "sending the consolidated notification" );
+
+                sendNotificationPerMultiModule( messageId, buildDefnIndex, buildResultIndex, consolidatedNotifiers );
+
+                consolidatedResult.clear();
+
+            }
+
+        }
+        catch ( TaskQueueManagerException e )
+        {
+            log.error( e.getMessage(), e );
+        }
+        catch ( ContinuumStoreException e )
+        {
+            log.error( e.getMessage(), e );
+        }
+
+    }
+
+    private void sendNotificationPerMultiModule( String messageId, int buildDefnIndex, int buildResultIndex,
+                       List<ProjectNotifier> consolidatedNotifiers )
+    {
+        Set<Project> projects = consolidatedResult.keySet();
+
+        Map<String, List<ProjectNotifier>> notifiersMap = new HashMap<String, List<ProjectNotifier>>();
+
+        getConsolidatedProjectGroupNotifiers( consolidatedNotifiers, notifiersMap );
+
+        for ( String notifierType : notifiersMap.keySet() )
+        {
+            //Project
+            List<MessageContext> contexts = new ArrayList<MessageContext>();
+            for ( Project p : projects )
+            {
+                Object obj[] = consolidatedResult.get( p );
+                MessageContext context = new MessageContext();
+                BuildDefinition buildDfn = (BuildDefinition) obj[buildDefnIndex];
+                BuildResult bdResult = (BuildResult) obj[buildResultIndex];
+                context.setProject( p );
+                context.setBuildDefinition( buildDfn );
+                context.setNotifier( notifiersMap.get( notifierType ) );
+                if ( bdResult != null )
+                {
+                    context.setBuildResult( bdResult );
+                }
+                contexts.add( context );
+
+            }
+            sendNotification( messageId, contexts );
+        }
+    }
+
+    private void getConsolidatedProjectGroupNotifiers( List<ProjectNotifier> notifiers,
+                                                       Map<String, List<ProjectNotifier>> notifiersMap )
+    {
+        // perform the project group level notifications
+        if ( !notifiers.isEmpty() )
+        {
+            for ( ProjectNotifier projectNotifier : notifiers )
+            {
+                List<ProjectNotifier> projectNotifiers = notifiersMap.get( projectNotifier.getType() );
+                if ( projectNotifiers == null )
+                {
+                    projectNotifiers = new ArrayList<ProjectNotifier>();
+                }
+
+                if ( !projectNotifier.isEnabled() )
+                {
+                    log.info( projectNotifier.getType() + " projectNotifier (id=" + projectNotifier.getId()
+                        + ") is disabled." );
+
+                    continue;
+                }
+
+                if ( !projectNotifier.isConsolidateNotification() )
+                {
+                    log.info( projectNotifier.getType() + " projectNotifier (id=" + projectNotifier.getId()
+                        + ") is not consolidated notification type." );
+
+                    continue;
+                }
+
+                projectNotifiers.add( projectNotifier );
+                notifiersMap.put( projectNotifier.getType(), projectNotifiers );
+            }
+        }
+    }
+
+    private List<ProjectNotifier> getConsolidatedNotifiers( List<ProjectNotifier> notifiers )
+    {
+        List<ProjectNotifier> consolidatedNotifiers = new ArrayList<ProjectNotifier>();
+        for ( ProjectNotifier notifier : notifiers )
+        {
+            if ( notifier.isConsolidateNotification() )
+            {
+                consolidatedNotifiers.add( notifier );
+            }
+        }
+
+        return consolidatedNotifiers;
+    }
+
+
+    private boolean isPartOfMultiModule( Map<Project, Object[]> result, Project project )
+    {
+        if ( project.getParent() == null && !result.isEmpty() )
+        {
+            return false;
+        }
+
+        for ( Project p : result.keySet() )
+        {
+
+            String parentDependencyId = getDependencyId( project.getParent() );           
+
+            if ( getProjectId( p ).equals( parentDependencyId ) )
+            {
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    private String getDependencyId( ProjectDependency project )
+    {
+        return project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getVersion();
+    }
+
+    private String getProjectId( Project project )
+    {
+        String groupId;
+
+        String artifactId;
+
+        if ( project.getGroupId() == null )
+        {
+            groupId = project.getName();
+        }
+        else
+        {
+            groupId = project.getGroupId();
+        }
+
+        if ( project.getArtifactId() == null )
+        {
+            artifactId = project.getName();
+        }
+        else
+        {
+            artifactId = project.getArtifactId();
+        }
+
+        return groupId + ":" + artifactId + ":" + project.getVersion();
+    }
+
     private void sendNotification( String messageId, Project project, BuildDefinition buildDefinition,
                                    BuildResult buildResult )
     {
+        sendNotification( messageId, project, buildDefinition, buildResult, true );
+    }
+
+    private void sendNotification( String messageId, Project project, BuildDefinition buildDefinition,
+                                   BuildResult buildResult, boolean includeConsolidatedNotifier )
+    {
         //Map context = new HashMap();
 
         // ----------------------------------------------------------------------
@@ -130,10 +375,10 @@
                 projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( project.getProjectGroup().getId() );
 
             Map<String, List<ProjectNotifier>> notifiersMap = new HashMap<String, List<ProjectNotifier>>();
-            
+
             getProjectNotifiers( project, notifiersMap );
-            getProjectGroupNotifiers( projectGroup, notifiersMap );
-            
+            getProjectGroupNotifiers( projectGroup, notifiersMap, includeConsolidatedNotifier );
+
             for ( String notifierType : notifiersMap.keySet() )
             {
                 MessageContext context = new MessageContext();
@@ -147,7 +392,6 @@
 
                 List<ProjectNotifier> projectNotiiers = notifiersMap.get( notifierType );
                 context.setNotifier( projectNotiiers );
-
                 sendNotification( messageId, context );
             }
         }
@@ -163,10 +407,10 @@
         {
             ProjectGroup group =
                 projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( projectScmRoot.getProjectGroup().getId() );
-            
+
             Map<String, List<ProjectNotifier>> notifiersMap = new HashMap<String, List<ProjectNotifier>>();
             getProjectGroupNotifiers( group, notifiersMap );
-            
+
             for ( String notifierType : notifiersMap.keySet() )
             {
                 MessageContext context = new MessageContext();
@@ -200,7 +444,23 @@
             log.error( "Error while trying to use the " + notifierType + " notifier.", e );
         }
     }
-    
+
+    private void sendNotification( String messageId, List<MessageContext> context )
+    {
+        String notifierType = context.get( 0 ).getNotifiers().get( 0 ).getType();
+
+        try
+        {
+            Notifier notifier = notifierManager.getNotifier( notifierType );
+
+            notifier.sendMessage( messageId, context );
+        }
+        catch ( NotificationException e )
+        {
+            log.error( "Error while trying to use the " + notifierType + " notifier.", e );
+        }
+    }
+
     private void getProjectNotifiers( Project project, Map<String, List<ProjectNotifier>> notifiersMap )
     {
         if ( project.getNotifiers() != null )
@@ -226,9 +486,15 @@
             }
         }
     }
-    
-    private void getProjectGroupNotifiers( ProjectGroup projectGroup, Map<String, List<ProjectNotifier>>  notifiersMap )
+
+    private void getProjectGroupNotifiers( ProjectGroup projectGroup, Map<String, List<ProjectNotifier>> notifiersMap )
     {
+        getProjectGroupNotifiers( projectGroup, notifiersMap, true );
+    }
+
+    private void getProjectGroupNotifiers( ProjectGroup projectGroup, Map<String, List<ProjectNotifier>> notifiersMap,
+                                           boolean includeConsolidatedNotifier )
+    {
         // perform the project group level notifications
         if ( projectGroup.getNotifiers() != null )
         {
@@ -242,12 +508,20 @@
 
                 if ( !projectNotifier.isEnabled() )
                 {
-                    log.info( projectNotifier.getType() + " projectNotifier (id=" + projectNotifier.getId() +
-                        ") is disabled." );
+                    log.info( projectNotifier.getType() + " projectNotifier (id=" + projectNotifier.getId()
+                        + ") is disabled." );
 
                     continue;
                 }
 
+                if ( projectNotifier.isConsolidateNotification() && !includeConsolidatedNotifier )
+                {
+                    log.info( projectNotifier.getType() + " projectNotifier (id=" + projectNotifier.getId()
+                        + ") is part of notifier(s) to be consolidated." );
+
+                    continue;
+                }
+
                 projectNotifiers.add( projectNotifier );
                 notifiersMap.put( projectNotifier.getType(), projectNotifiers );
             }
Index: continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
===================================================================
--- continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java	(revision 732838)
+++ continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java	(working copy)
@@ -1846,6 +1846,8 @@
         notif.setSendOnWarning( notifier.isSendOnWarning() );
 
         notif.setSendOnScmFailure( notifier.isSendOnScmFailure() );
+        
+        notif.setConsolidateNotification( notifier.isConsolidateNotification() );
 
         notif.setConfiguration( notifier.getConfiguration() );
 
@@ -1878,6 +1880,8 @@
         notif.setSendOnScmFailure( notifier.isSendOnScmFailure() );
 
         notif.setConfiguration( notifier.getConfiguration() );
+        
+        notif.setConsolidateNotification( notifier.isConsolidateNotification() );
 
         notif.setType( notifier.getType() );
 
Index: continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/common.vm
===================================================================
--- continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/common.vm	(revision 732838)
+++ continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/common.vm	(working copy)
@@ -14,6 +14,7 @@
  * limitations under the License.
  *#
 #macro( shellBuildResult )
+Project name : $project.name
 Online report : $reportUrl
 
 #if ( $build )

