diff --git a/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java b/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java
index d0dbe2884416e28e9cb14e8357034eab2e9b4e4c..8a5fd268c4b844322d5e1c4ba8986f86c321ee59 100644
--- a/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java
+++ b/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java
@@ -24,11 +24,13 @@ import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.List;
+import java.util.UUID;
 
 import org.olat.admin.user.UserSearchController;
 import org.olat.basesecurity.events.MultiIdentityChosenEvent;
 import org.olat.basesecurity.events.SingleIdentityChosenEvent;
 import org.olat.commons.calendar.model.KalendarEvent;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.form.flexible.impl.components.SimpleText;
@@ -46,13 +48,14 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.ContactMessage;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailNotificationEditController;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.modules.co.ContactFormController;
 
 import de.bps.course.nodes.DENCourseNode;
@@ -87,13 +90,15 @@ public class DENManageParticipantsController extends BasicController {
 	private CloseableModalController manageParticipantsModalCntrl;
 	
 	private DENManager denManager;
+	private MailManager mailManager;
 	
 	public DENManageParticipantsController(UserRequest ureq, WindowControl wControl, OLATResourceable ores, DENCourseNode courseNode) {
 		super(ureq, wControl);
 		
 		this.ores = ores;
 		this.courseNode = courseNode;
-		this.denManager = DENManager.getInstance();
+		denManager = DENManager.getInstance();
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		
 		//prepare list of enrolled participants
 		dateList = denManager.getDENEvents(ores.getResourceableId(), courseNode.getIdent());
@@ -242,31 +247,35 @@ public class DENManageParticipantsController extends BasicController {
 			}
 		} else if(source == addedNotificationCtr && event == Event.DONE_EVENT) {
 			if(addedNotificationCtr.getMailTemplate() != null) {
-			  	List<Identity> ccIdentities = new ArrayList<Identity>();
+				Identity sender = ureq.getIdentity();
+				MailerResult result = new MailerResult();
+				String metaId = UUID.randomUUID().toString().replace("-", "");
+				MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
+				MailBundle[] bundles = mailManager.makeMailBundles(context, added, addedNotificationCtr.getMailTemplate(), sender, metaId, result);
+				result.append(mailManager.sendMessage(bundles));
 				if(addedNotificationCtr.getMailTemplate().getCpfrom()) {
-					ccIdentities.add(ureq.getIdentity());
-				} else {
-					ccIdentities = null;
+					MailBundle ccBundles = mailManager.makeMailBundle(context, sender, addedNotificationCtr.getMailTemplate(), sender, metaId, result);
+					result.append(mailManager.sendMessage(ccBundles));
 				}
-				//fxdiff VCRP-16: intern mail system
-				MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-				MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, added, null, addedNotificationCtr.getMailTemplate(), ureq.getIdentity());
-				MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale());
+				MailHelper.printErrorsAndWarnings(result, getWindowControl(), ureq.getLocale());
 			}
 			notificationCmc.deactivate();
 			added.clear();
 		} else if(source == removedNotificationCtr && event == Event.DONE_EVENT) {
 			if(removedNotificationCtr.getMailTemplate() != null) {
-			  	List<Identity> ccIdentities = new ArrayList<Identity>();
-				if(addedNotificationCtr.getMailTemplate().getCpfrom()) {
-					ccIdentities.add(ureq.getIdentity());
-				} else {
-					ccIdentities = null;
-				}
+
 				//fxdiff VCRP-16: intern mail system
+				Identity sender = ureq.getIdentity();
+				MailerResult result = new MailerResult();
+				String metaId = UUID.randomUUID().toString().replace("-", "");
 				MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-				MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, added, null, addedNotificationCtr.getMailTemplate(), ureq.getIdentity());
-				MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale());
+				MailBundle[] bundles = mailManager.makeMailBundles(context, added, addedNotificationCtr.getMailTemplate(), sender, metaId, result);
+				result.append(mailManager.sendMessage(bundles));
+				if(addedNotificationCtr.getMailTemplate().getCpfrom()) {
+					MailBundle ccBundle = mailManager.makeMailBundle(context, sender, addedNotificationCtr.getMailTemplate(), sender, metaId, result);
+					result.append(mailManager.sendMessage(ccBundle));
+				}
+				MailHelper.printErrorsAndWarnings(result, getWindowControl(), ureq.getLocale());
 			}
 			notificationCmc.deactivate();
 			removed.clear();
diff --git a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java
index 2ceecf342b66004d743f7087840639a5780806cc..48a48eadece5d40e0076f90010b07a57128bda57 100644
--- a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java
+++ b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationMailHelper.java
@@ -32,17 +32,14 @@
 
 package de.tuchemnitz.wizard.workflows.coursecreation;
 
-import org.apache.velocity.VelocityContext;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.translator.Translator;
-import org.olat.core.id.Identity;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Util;
-import org.olat.core.util.mail.MailContext;
-import org.olat.core.util.mail.MailContextImpl;
-import org.olat.core.util.mail.MailTemplate;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 
 import de.tuchemnitz.wizard.workflows.coursecreation.model.CourseCreationConfiguration;
 
@@ -104,16 +101,11 @@ public class CourseCreationMailHelper {
 		body += translator.translate("mail.body.5");
 		body += translator.translate("mail.body.6");
 		body += translator.translate("mail.body.greetings");
-
-		MailTemplate template = new MailTemplate(subject, body, null) {
-			@Override
-			@SuppressWarnings("unused") 
-			public void putVariablesInMailContext(VelocityContext context, Identity identity) {
-				// nothing to do
-			}
-		};
-		//fxdiff VCRP-16: intern mail system
-		return MailerWithTemplate.getInstance().sendRealMail(ureq.getIdentity(), template);
+		
+		MailBundle bundle = new MailBundle();
+		bundle.setToId(ureq.getIdentity());
+		bundle.setContent(subject, body);
+		return CoreSpringFactory.getImpl(MailManager.class).sendExternMessage(bundle, null);
 	}
 
 }
diff --git a/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java b/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java
index 2ddf6cd41113714870ec8c2a666eb68451a53403..a6db6c372d5bace6e457a2ece0aaa11909a157f6 100644
--- a/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java
+++ b/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java
@@ -75,13 +75,14 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
 import org.olat.core.logging.AssertException;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
 import org.olat.core.util.mail.MailNotificationEditController;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.session.UserSessionManager;
 import org.olat.group.ui.main.OnlineIconRenderer;
 import org.olat.instantMessaging.InstantMessagingModule;
@@ -153,6 +154,7 @@ public class GroupController extends BasicController {
 	private InstantMessagingModule imModule;
 	private InstantMessagingService imService;
 	private UserSessionManager sessionManager;
+	private MailManager mailManager;
 	
 	public Object userObject;
 
@@ -184,6 +186,7 @@ public class GroupController extends BasicController {
 		imService = CoreSpringFactory.getImpl(InstantMessagingService.class);
 		userManager = CoreSpringFactory.getImpl(UserManager.class);
 		sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		
 		Roles roles = ureq.getUserSession().getRoles();
 		BaseSecurityModule securityModule = CoreSpringFactory.getImpl(BaseSecurityModule.class);
@@ -523,22 +526,21 @@ public class GroupController extends BasicController {
 
 		// send the notification mail
 		if (mailTemplate != null) {
-			MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 			Identity sender = null; // means no sender in footer
-			if (this.showSenderInRemovMailFooter) {
+			if (showSenderInRemovMailFooter) {
 				sender = ureq.getIdentity();
 			}
-			List<Identity> ccIdentities = new ArrayList<Identity>();
-			if(mailTemplate.getCpfrom()) {
-				ccIdentities.add(ureq.getIdentity());// add sender to cc-list
-			} else {
-				ccIdentities = null;	
-			}
-			//fxdiff VCRP-16: intern mail system
+
 			String metaId = UUID.randomUUID().toString();
 			MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-			MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, toBeRemoved, ccIdentities, mailTemplate, sender, metaId);
-			MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale());
+			MailerResult result = new MailerResult();
+			MailBundle[] bundles = mailManager.makeMailBundles(context, toBeRemoved, mailTemplate, sender, metaId, result);
+			result.append(mailManager.sendMessage(bundles));
+			if(mailTemplate.getCpfrom()) {
+				MailBundle ccBundle = mailManager.makeMailBundle(context, ureq.getIdentity(), mailTemplate, sender, metaId, result);
+				result.append(mailManager.sendMessage(ccBundle));
+			}
+			MailHelper.printErrorsAndWarnings(result, getWindowControl(), ureq.getLocale());
 		}
 	}
 
@@ -571,22 +573,21 @@ public class GroupController extends BasicController {
 		// send the notification mail fro added users
 		StringBuilder errorMessage = new StringBuilder();
 		if (mailTemplate != null) {
-			MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 			Identity sender = null; // means no sender in footer
-			if (this.showSenderInAddMailFooter) {
+			if (showSenderInAddMailFooter) {
 				sender = ureq.getIdentity();
 			}
-			List<Identity> ccIdentities = new ArrayList<Identity>();
-			if(mailTemplate.getCpfrom()) {
-				ccIdentities.add(ureq.getIdentity());// add sender to cc-list
-			} else {
-				ccIdentities = null;	
-			}
-			//fxdiff VCRP-16: intern mail system
+			
 			String metaId = UUID.randomUUID().toString();
 			MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-			MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, identitiesAddedEvent.getAddedIdentities(), ccIdentities, mailTemplate, sender, metaId);
-			MailHelper.appendErrorsAndWarnings(mailerResult, errorMessage, infoMessage, ureq.getLocale());
+			MailerResult result = new MailerResult();
+			MailBundle[] bundles = mailManager.makeMailBundles(context, identitiesAddedEvent.getAddedIdentities(), mailTemplate, sender, metaId, result);
+			result.append(mailManager.sendMessage(bundles));
+			if(mailTemplate.getCpfrom()) {
+				MailBundle ccBundle = mailManager.makeMailBundle(context, ureq.getIdentity(), mailTemplate, sender, metaId, result);
+				result.append(mailManager.sendMessage(ccBundle));
+			}
+			MailHelper.appendErrorsAndWarnings(result, errorMessage, infoMessage, ureq.getLocale());
 		}
 		// report any errors on screen
 		if (infoMessage.length() > 0) getWindowControl().setWarning(infoMessage.toString());
diff --git a/src/main/java/org/olat/admin/user/SendTokenToUserForm.java b/src/main/java/org/olat/admin/user/SendTokenToUserForm.java
index 776364bde82f94043206e1779a983104bc17a2e2..a5c63b78c4ae61e9ab6539e23bd87e2e47cd5a20 100644
--- a/src/main/java/org/olat/admin/user/SendTokenToUserForm.java
+++ b/src/main/java/org/olat/admin/user/SendTokenToUserForm.java
@@ -22,10 +22,10 @@ package org.olat.admin.user;
 
 import java.util.Locale;
 
-import org.apache.velocity.VelocityContext;
 import org.olat.basesecurity.Authentication;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.BaseSecurityModule;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -42,9 +42,9 @@ import org.olat.core.id.UserConstants;
 import org.olat.core.util.Encoder;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nManager;
-import org.olat.core.util.mail.MailTemplate;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.registration.RegistrationManager;
 import org.olat.registration.TemporaryKey;
 
@@ -63,10 +63,12 @@ public class SendTokenToUserForm extends FormBasicController {
 	private TextElement mailText;
 	
 	private String dummyKey;
+	private MailManager mailManager;
 
 	public SendTokenToUserForm(UserRequest ureq, WindowControl wControl, Identity treatedIdentity) {
 		super(ureq, wControl);
 		user = treatedIdentity;
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		initForm(ureq);
 	}
 	
@@ -156,21 +158,16 @@ public class SendTokenToUserForm extends FormBasicController {
 			return;
 		}
 		String body = text.replace(dummyKey, tk.getRegistrationKey());
-
 		Translator userTrans = Util.createPackageTranslator(RegistrationManager.class, locale) ;
-		String subject = userTrans.translate("pwchange.subject");
-		MailTemplate mailTempl = new MailTemplate(subject, body, null) {
-			@Override
-			public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-				// nothing to do
-			}
-		};
-		//fxdiff VCRP-16: intern mail system
-		MailerResult result = MailerWithTemplate.getInstance().sendRealMail(user, mailTempl);
+
+		MailBundle bundle = new MailBundle();
+		bundle.setToId(user);
+		bundle.setContent(userTrans.translate("pwchange.subject"), body);
+		MailerResult result = mailManager.sendExternMessage(bundle, null);
 		if(result.getReturnCode() == 0) {
 			showInfo("email.sent");
 		} else {
 			showInfo("email.notsent");
 		}
 	}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java
index ba7fd1259b6b488407778ac3a42c87b368ef994c..36dcd9b7c0880f60031bda6890c93ce53d2a8b64 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java
+++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java
@@ -54,9 +54,9 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailPackage;
-import org.olat.core.util.mail.MailTemplate;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.login.auth.OLATAuthManager;
@@ -269,8 +269,6 @@ public class UserBulkChangeManager extends BasicManager {
 	}
 	
 	public void sendLoginDeniedEmail(Identity identity) {
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
-
 		String[] args = new String[] {
 				identity.getName(),//0: changed users username
 				identity.getUser().getProperty(UserConstants.EMAIL, null),// 1: changed users email address
@@ -281,15 +279,12 @@ public class UserBulkChangeManager extends BasicManager {
 		String lang = identity.getUser().getPreferences().getLanguage();
 		Locale locale = I18nManager.getInstance().getLocaleOrDefault(lang);
 		Translator translator = Util.createPackageTranslator(SystemRolesAndRightsController.class, locale);
-		String subject = translator.translate("mailtemplate.login.denied.subject", args);
-		String body = translator.translate("mailtemplate.login.denied.body", args);
-		MailTemplate template = new MailTemplate(subject, body, null){
-			@Override
-			public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-				//
-			}
-		};
-		mailer.sendRealMail(identity, template);
+
+		MailBundle bundle = new MailBundle();
+		bundle.setToId(identity);
+		bundle.setContent(translator.translate("mailtemplate.login.denied.subject", args),
+			translator.translate("mailtemplate.login.denied.body", args));
+		CoreSpringFactory.getImpl(MailManager.class).sendExternMessage(bundle, null);
 	}
 
 	public String evaluateValueWithUserContext(String valToEval, Context vcContext) {
diff --git a/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java b/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java
index 63d50a0003c85d179e358c86680a4fc202165439..22f8838d81d86e035a7f87682202d1f32633c75d 100644
--- a/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java
+++ b/src/main/java/org/olat/admin/user/delete/BulkDeleteController.java
@@ -24,12 +24,10 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
-import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
-
 import org.olat.admin.securitygroup.gui.UserControllerFactory;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -44,10 +42,10 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.id.Identity;
-import org.olat.core.logging.Tracing;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.mail.ContactList;
-import org.olat.core.util.mail.Emailer;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 
 public class BulkDeleteController extends BasicController {
 	
@@ -61,12 +59,15 @@ public class BulkDeleteController extends BasicController {
 	
 	private TableController tblCtrFound, tblCtrNotfound;
 	private Link btnNext;
+	
+	private final MailManager mailService;
 
 	public BulkDeleteController(UserRequest ureq, WindowControl wControl, String userlist, String reason) {
 		super(ureq, wControl);
 		
 		this.userlist = userlist;
 		this.reason = reason;
+		mailService = CoreSpringFactory.getImpl(MailManager.class);
 		
 		vc = createVelocityContainer("bulkdelete");
 		processUserList(this.userlist);
@@ -82,7 +83,7 @@ public class BulkDeleteController extends BasicController {
 			tblCtrNotfound = new TableController(null, ureq, wControl, getTranslator());
 			listenTo(tblCtrNotfound);
 			tblCtrNotfound.addColumnDescriptor(new DefaultColumnDescriptor("table.col.login", 0, null, ureq.getLocale()));
-			TableDataModel tblData = new LoginTableDataModel(lstLoginsNotfound);
+			TableDataModel<String> tblData = new LoginTableDataModel(lstLoginsNotfound);
 			tblCtrNotfound.setTableDataModel(tblData);
 			
 			vc.put("table.users.notfound", tblCtrNotfound.getInitialComponent());
@@ -153,25 +154,20 @@ public class BulkDeleteController extends BasicController {
 				reason,
 				df.format(new Date())
 		};
-		
-		String subject = translate("mail.subject");
-		String body = getTranslator().translate("mail.body", bodyArgs);
-		
+
 		ContactList cl = new ContactList(recipient);
 		cl.add(recipient);
 		cl.add(ureq.getIdentity());
-		List<ContactList> lstAddrTO = new ArrayList<ContactList>();
-		lstAddrTO.add(cl);
-		
-		Emailer mailer = new Emailer(ureq.getLocale());
+
 		try {
-			//fxdiff VCRP-16: intern mail system
-			mailer.sendEmail(null, lstAddrTO, subject, body, null);
-		} catch (AddressException e) {
-			Tracing.createLoggerFor(BulkDeleteController.class).error("Notificatoin mail for bulk deletion could not be sent");
-		} catch (MessagingException e) {
-			Tracing.createLoggerFor(BulkDeleteController.class).error("Notificatoin mail for bulk deletion could not be sent");
-		}
+			MailBundle bundle = new MailBundle();
+			bundle.setFrom(WebappHelper.getMailConfig("mailReplyTo"));
+			bundle.setContent(translate("mail.subject"), translate("mail.body", bodyArgs));
+			bundle.setContactList(cl);
+			mailService.sendMessage(bundle);
+		} catch (Exception e) {
+			logError("Notificatoin mail for bulk deletion could not be sent", null);
+		} 
 	}
 	
 	public List<Identity> getToDelete() {
@@ -184,9 +180,9 @@ public class BulkDeleteController extends BasicController {
 	}
 }
 
-class LoginTableDataModel extends DefaultTableDataModel {
+class LoginTableDataModel extends DefaultTableDataModel<String> {
 
-	public LoginTableDataModel(List logins) {
+	public LoginTableDataModel(List<String> logins) {
 		super(logins);
 	}
 
@@ -197,12 +193,10 @@ class LoginTableDataModel extends DefaultTableDataModel {
 
 	@Override
 	public Object getValueAt(int row, int col) {
-		String login = (String)getObject(row);
-		
+		String login = getObject(row);
 		switch (col) {
 			case 0: return login;
 			default: return "error";
 		}
 	}
-	
 }
diff --git a/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java b/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java
index 95fca3260049e64ef667bbdf17f0866d2509e906..c2142e1ae9cd13d6ac703bd380d8fb60eec77eb2 100644
--- a/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java
+++ b/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java
@@ -28,9 +28,7 @@ package org.olat.admin.user.delete.service;
 import java.io.File;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
@@ -57,9 +55,10 @@ import org.olat.core.util.Util;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.SyncerExecutor;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.course.assessment.EfficiencyStatementManager;
 import org.olat.properties.Property;
@@ -101,6 +100,7 @@ public class UserDeletionManager extends BasicManager {
 	private DeletionModule deletionModule;
 	private CoordinatorManager coordinatorManager;
 	private BaseSecurity securityManager;
+	private MailManager mailManager;
 
 	/**
 	 * [used by spring]
@@ -119,6 +119,15 @@ public class UserDeletionManager extends BasicManager {
 	public void setBaseSecurityManager(BaseSecurity securityManager) {
 		this.securityManager = securityManager;
 	}
+	
+	/**
+	 * [used by Spring]
+	 * @param mailManager
+	 */
+	public void setMailManager(MailManager mailManager) {
+		this.mailManager = mailManager;
+	}
+
 
 	/**
 	 * @return Singleton.
@@ -136,7 +145,6 @@ public class UserDeletionManager extends BasicManager {
 			boolean isTemplateChanged, String keyEmailSubject, String keyEmailBody, Identity sender, Translator pT ) {
 		StringBuilder buf = new StringBuilder();
 		if (template != null) {
-			MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 			template.addToContext("responseTo", deletionModule.getEmailResponseTo());
 			for (Iterator<Identity> iter = selectedIdentities.iterator(); iter.hasNext();) {
 				Identity identity = iter.next();
@@ -148,15 +156,21 @@ public class UserDeletionManager extends BasicManager {
 				} 
 				template.putVariablesInMailContext(template.getContext(), identity);
 				logDebug(" Try to send Delete-email to identity=" + identity.getName() + " with email=" + identity.getUser().getProperty(UserConstants.EMAIL, null));
-				List<Identity> ccIdentities = new ArrayList<Identity>();
+				Identity ccIdentity = null;
+				
+				MailerResult result = new MailerResult();
+				MailBundle bundle = mailManager.makeMailBundle(null, identity, template, sender, null, result);
+				if(bundle != null) {
+					mailManager.sendMessage(bundle);
+				}
 				if(template.getCpfrom()) {
-					ccIdentities.add(sender);
-				} else {
-					ccIdentities = null;	
+					MailBundle ccBundle = mailManager.makeMailBundle(null, ccIdentity, template, sender, null, result);
+					if(ccBundle != null) {
+						mailManager.sendMessage(ccBundle);
+					}
 				}
-				MailerResult mailerResult = mailer.sendMailAsSeparateMails(null, Collections.singletonList(identity), ccIdentities, template, sender);
 				
-				if (mailerResult.getReturnCode() != MailerResult.OK) {
+				if (result.getReturnCode() != MailerResult.OK) {
 					buf.append(pT.translate("email.error.send.failed", new String[] {identity.getUser().getProperty(UserConstants.EMAIL, null), identity.getName()} )).append("\n");
 				}
 				logAudit("User-Deletion: Delete-email send to identity=" + identity.getName() + " with email=" + identity.getUser().getProperty(UserConstants.EMAIL, null));
diff --git a/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml b/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml
index 1bf70150aae756cc5534b74590aff5d6b161498d..a7814edc0b973e5a69ce45744e35dd491a5b75e4 100644
--- a/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml
+++ b/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml
@@ -3,14 +3,13 @@
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="http://www.springframework.org/schema/beans 
-                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
-                        http://www.springframework.org/schema/context 
-                        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+                        http://www.springframework.org/schema/beans/spring-beans.xsd">
                         
 	<bean id="infoMessageFrontendManager" class="org.olat.commons.info.manager.InfoMessageFrontendManagerImpl">
 		<property name="coordinatorManager" ref="coordinatorManager"/>
-	  <property name="infoMessageManager" ref="infoMessageManager"/>
-	  <property name="infoSubscriptionManager" ref="infoSubscriptionManager"/>
+		<property name="infoMessageManager" ref="infoMessageManager"/>
+		<property name="infoSubscriptionManager" ref="infoSubscriptionManager"/>
+		<property name="mailManager" ref="mailManager"/>
 	</bean>
 
 	<bean id="infoMessageManager" class="org.olat.commons.info.manager.InfoMessageManagerImpl">
diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
index 1172466c5b0c0f20c3f3e9bbfeecc24ec725c34d..d8b89a666147a2877cd6287a6768110af78313fe 100644
--- a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
+++ b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
@@ -20,16 +20,12 @@
 
 package org.olat.commons.info.manager;
 
-import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 
-import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
-
 import org.olat.commons.info.model.InfoMessage;
 import org.olat.commons.info.notification.InfoSubscriptionManager;
 import org.olat.core.id.Identity;
@@ -39,9 +35,11 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.MultiUserEvent;
 import org.olat.core.util.mail.ContactList;
-import org.olat.core.util.mail.Emailer;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
+import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailerResult;
 
 /**
  * 
@@ -53,10 +51,19 @@ import org.olat.core.util.mail.MailContextImpl;
  */
 public class InfoMessageFrontendManagerImpl extends BasicManager implements InfoMessageFrontendManager {
 	
+	private MailManager mailManager;
 	private CoordinatorManager coordinatorManager;
 	private InfoMessageManager infoMessageManager;
 	private InfoSubscriptionManager infoSubscriptionManager;
 
+	/**
+	 * [used by Spring]
+	 * @param mailManager
+	 */
+	public void setMailManager(MailManager mailManager) {
+		this.mailManager = mailManager;
+	}
+
 	/**
 	 * [used by Spring]
 	 * @param coordinatorManager
@@ -97,7 +104,6 @@ public class InfoMessageFrontendManagerImpl extends BasicManager implements Info
 		
 		boolean send = false;
 		if(tos != null && !tos.isEmpty()) {
-			Emailer mailer = new Emailer(from, false);
 			Set<Long> identityKeySet = new HashSet<Long>();
 			ContactList contactList = new ContactList("Infos");
 			for(Identity to:tos) {
@@ -105,7 +111,7 @@ public class InfoMessageFrontendManagerImpl extends BasicManager implements Info
 				contactList.add(to);
 				identityKeySet.add(to.getKey());
 			}
-			List<ContactList> contacts = Collections.singletonList(contactList);
+			
 			try {
 				String subject = null;
 				String body = null;
@@ -121,10 +127,15 @@ public class InfoMessageFrontendManagerImpl extends BasicManager implements Info
 				}
 				//fxdiff VCRP-16: intern mail system
 				MailContext context = new MailContextImpl(mailFormatter.getBusinessPath());
-				send = mailer.sendEmail(context, contacts, subject, body, null);
-			} catch (AddressException e) {
-				logError("Cannot send info messages", e);
-			} catch (MessagingException e) {
+				MailBundle bundle = new MailBundle();
+				bundle.setContext(context);
+				bundle.setFromId(from);
+				bundle.setContactList(contactList);
+				bundle.setContent(subject, body);
+				
+				MailerResult result = mailManager.sendMessage(bundle);
+				send = result.isSuccessful();
+			} catch (Exception e) {
 				logError("Cannot send info messages", e);
 			}
 		}
diff --git a/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java b/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java
index c2929ee5bfc29eee0604ee344f97c5c844bb33b4..2b6f558b2105448a9a8cce9078a301f3f26e1291 100644
--- a/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java
+++ b/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java
@@ -36,9 +36,11 @@ import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.LogFileParser;
+import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.WebappHelper;
-import org.olat.core.util.mail.manager.MailManager;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 
 /**
  * Description:<br>
@@ -49,6 +51,8 @@ import org.olat.core.util.mail.manager.MailManager;
  * @author guido
  */
 public class ErrorFeedbackMailer implements Dispatcher {
+	
+	private static final OLog log = Tracing.createLoggerFor(ErrorFeedbackMailer.class);
 
 	private static final ErrorFeedbackMailer INSTANCE = new ErrorFeedbackMailer();
 
@@ -86,11 +90,15 @@ public class ErrorFeedbackMailer implements Dispatcher {
 					out.append(iter.next());
 				}
 			}
-			String to = WebappHelper.getMailConfig("mailError");
-			String subject = "Feedback from Error Nr.: " + errorNr;
+
 			String body = feedback + "\n------------------------------------------\n\n --- from user: " + username
 					+ " ---" + out.toString();
-			MailManager.getInstance().sendExternMessage(ident, null, null, to, null, null, null, subject, body, null, null);
+			
+			MailBundle bundle = new MailBundle();
+			bundle.setFromId(ident);
+			bundle.setTo(WebappHelper.getMailConfig("mailError"));
+			bundle.setContent("Feedback from Error Nr.: " + errorNr, body);
+			CoreSpringFactory.getImpl(MailManager.class).sendExternMessage(bundle, null);
 		} catch (Exception e) {
 			// error in recipient email address(es)
 			handleException(request, e);
@@ -102,9 +110,8 @@ public class ErrorFeedbackMailer implements Dispatcher {
 	private void handleException(HttpServletRequest request, Exception e) {
 		String feedback = request.getParameter("textarea");
 		String username = request.getParameter("username");
-		Tracing.logError("Error sending error feedback mail to OpenOLAT error support (" + WebappHelper.getMailConfig("mailError") + ") from: "
-				+ username + " with content: " + feedback, e, this.getClass());
-
+		log.error("Error sending error feedback mail to OpenOLAT error support (" + WebappHelper.getMailConfig("mailError") + ") from: "
+				+ username + " with content: " + feedback, e);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/core/gui/components/table/TableListProvider.java b/src/main/java/org/olat/core/gui/components/table/TableListProvider.java
index 9ec93354c43791aa33239112de97aaebfbd64027..ae0cfcdab351e2710462abefd6ed56d5bc6112b3 100644
--- a/src/main/java/org/olat/core/gui/components/table/TableListProvider.java
+++ b/src/main/java/org/olat/core/gui/components/table/TableListProvider.java
@@ -1,3 +1,22 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
 package org.olat.core.gui.components.table;
 
 import java.util.Set;
diff --git a/src/main/java/org/olat/core/util/filter/impl/NekoHTMLFilter.java b/src/main/java/org/olat/core/util/filter/impl/NekoHTMLFilter.java
index cf5fe75a6b05f082e546d346ed5386dd5b4ec3c5..25f2d82f84d7fdfce4c9c9342bf2613c328649f7 100644
--- a/src/main/java/org/olat/core/util/filter/impl/NekoHTMLFilter.java
+++ b/src/main/java/org/olat/core/util/filter/impl/NekoHTMLFilter.java
@@ -52,10 +52,14 @@ public class NekoHTMLFilter extends LogDelegator implements Filter {
 
 	@Override
 	public String filter(String original) {
+		return filter(original, false);
+	}
+	
+	public String filter(String original, boolean pretty) {
 		if (original == null) return null;
 		try {
 			SAXParser parser = new SAXParser();
-			HTMLHandler contentHandler = new HTMLHandler((int)((float)original.length() * 0.66f));
+			HTMLHandler contentHandler = new HTMLHandler((int)((float)original.length() * 0.66f), pretty);
 			parser.setContentHandler(contentHandler);
 			parser.parse(new InputSource(new StringReader(original)));
 			return contentHandler.toString();
@@ -75,7 +79,7 @@ public class NekoHTMLFilter extends LogDelegator implements Filter {
 		if (in == null) return null;
 		try {
 			SAXParser parser = new SAXParser();
-			HTMLHandler contentHandler = new HTMLHandler((int)(1000 * 0.66f));
+			HTMLHandler contentHandler = new HTMLHandler((int)(1000 * 0.66f), false);
 			parser.setContentHandler(contentHandler);
 			parser.parse(new InputSource(in));
 			return contentHandler.getContent();
@@ -113,10 +117,12 @@ public class NekoHTMLFilter extends LogDelegator implements Filter {
 		private boolean collect = true;
 		private boolean consumeBlanck = false;
 		private boolean consumeTitle = true;
+		private final boolean pretty;
 		private final StringBuilder sb;
 		private final StringBuilder title;
 		
-		public HTMLHandler(int size) {
+		public HTMLHandler(int size, boolean pretty) {
+			this.pretty = pretty;
 			sb = new StringBuilder(size);
 			title = new StringBuilder(32);
 		}
@@ -128,6 +134,13 @@ public class NekoHTMLFilter extends LogDelegator implements Filter {
 				collect = false;
 			// add a single whitespace before each block element but only if not there is not already a whitespace there
 			} else {
+				if(pretty) {
+					if("li".equals(elem)) {
+						sb.append("\u00B7 ");
+					} else if("br".equals(elem)) {
+						sb.append('\n');
+					}
+				}
 				if("title".equals(elem)) {
 					consumeTitle = true;
 				}
@@ -159,6 +172,9 @@ public class NekoHTMLFilter extends LogDelegator implements Filter {
 			if("script".equals(elem)) {
 				collect = true;
 			} else {
+				if(pretty && ("li".equals(elem) || "p".equals(elem))) {
+					sb.append('\n');
+				}
 				if("title".equals(elem)) {
 					consumeTitle = false;
 				}
diff --git a/src/main/java/org/olat/core/util/mail/ContactMessage.java b/src/main/java/org/olat/core/util/mail/ContactMessage.java
index 9b51cfffb456e14206d0885e429e17e8fa951032..55cab89a525f0da48d51d0e48b86ea5f129176d3 100644
--- a/src/main/java/org/olat/core/util/mail/ContactMessage.java
+++ b/src/main/java/org/olat/core/util/mail/ContactMessage.java
@@ -104,10 +104,7 @@ public class ContactMessage {
 	
 	private ContactList cleanEMailList(ContactList emailList) {
 		for (Identity identity: emailList.getIdentiEmails().values()) {
-			List<Identity> singleIdentityList = new ArrayList<Identity>();
-			singleIdentityList.add(identity);
-			MailerResult result = new MailerResult();
-			if(MailHelper.removeDisabledMailAddress(singleIdentityList, result).getFailedIdentites().size() > 0) {
+			if(MailHelper.isDisabledMailAddress(identity, null)) {
 				emailList.remove(identity);
 				if(!disabledIdentities.contains(identity)) {
 					disabledIdentities.add(identity);
diff --git a/src/main/java/org/olat/core/util/mail/Emailer.java b/src/main/java/org/olat/core/util/mail/Emailer.java
deleted file mode 100644
index 8d141f9eae83dcc1b433fedfdb307872539d1a29..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/mail/Emailer.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.  
-* <p>
-*/ 
-
-package org.olat.core.util.mail;
-
-
-import java.io.File;
-import java.util.List;
-import java.util.Locale;
-
-import javax.mail.MessagingException;
-import javax.mail.SendFailedException;
-import javax.mail.internet.AddressException;
-
-import org.olat.core.gui.translator.Translator;
-import org.olat.core.helpers.Settings;
-import org.olat.core.id.Identity;
-import org.olat.core.id.User;
-import org.olat.core.id.UserConstants;
-import org.olat.core.util.StringHelper;
-import org.olat.core.util.Util;
-import org.olat.core.util.WebappHelper;
-import org.olat.core.util.i18n.I18nManager;
-import org.olat.core.util.mail.manager.MailManager;
-
-/**
- * 
- * Helper class for sending emails. All mails sent by this class will have a
- * footer that includes a link to this OLAT installation
- * 
- * Initial Date: Feb 10, 2005
- * @author Sabina Jeger
- */
-public class Emailer {
-	private String mailfrom;
-	private Identity mailFromIdentity;
-	private String footer; // footer appended to the end of the mail
-
-	/**
-	 * Constructs an Emailer which derives its <b>mail from address </b> from the
-	 * mailfrom configuration in OLATContext. The <b>mail host </b> used to send the
-	 * email is taken from the <code>OLATContext</code>
-	 * @param locale locale that should be used for message localization
-	 */
-	public Emailer(Locale locale) {
-		this.mailfrom =  WebappHelper.getMailConfig("mailReplyTo");
-		// initialize the mail footer with info about this OLAt installation
-		Translator trans = Util.createPackageTranslator(Emailer.class, locale);
-		footer = trans.translate("footer.no.userdata", new String[] { Settings.getServerContextPathURI() });
-	}
-
-	//fxdiff
-	public String getFooter() {
-		return footer;
-	}
-
-	public void setFooter(String footer) {
-		this.footer = footer;
-	}
-
-	/**
-	 * Constructs an Emailer which derives its <b>mail from address </b> from the
-	 * given <code>Identity</code>. The <b>mail host </b> used to send the
-	 * email is taken from the <code>OLATContext</code>
-	 * <p>
-	 * The <code>boolean</code> parameter determines which email address is
-	 * used.
-	 * <UL>
-	 * <LI><b>true: </b> <br>
-	 * <UL>
-	 * <LI>try first the Institutional email</LI>
-	 * <LI>if not defined, take user defined email</LI>
-	 * </UL>
-	 * </LI>
-	 * <LI><b>false: </b> <br>
-	 * <UL>
-	 * <LI>take user defined email</LI>
-	 * </UL>
-	 * </LI>
-	 * </UL>
-	 * 
-	 * @param mailFromIdentity <b>not null </b>, containing the senders e-mail
-	 * @param tryInstitutionalEmail specifies email address priority order
-	 */
-	public Emailer(Identity mailFromIdentity, boolean tryInstitutionalEmail) {
-		String myMailfrom = mailFromIdentity.getUser().getProperty(UserConstants.EMAIL, null);
-		if (tryInstitutionalEmail) {
-			String tmpFrom = mailFromIdentity.getUser().getProperty(UserConstants.INSTITUTIONALEMAIL, null);
-			if (StringHelper.containsNonWhitespace(tmpFrom)) {
-				myMailfrom = tmpFrom;
-			}
-		}
-		this.mailfrom = myMailfrom;
-		//fxdiff VCRP-16: intern mail system
-		this.mailFromIdentity = mailFromIdentity;
-		// initialize the mail footer with infos about this OLAT installation and the user who sent the mail
-		User user = mailFromIdentity.getUser();
-		Locale locale = I18nManager.getInstance().getLocaleOrDefault(user.getPreferences().getLanguage());
-		footer = MailHelper.getMailFooter(locale, mailFromIdentity);
-	}
-
-	/**
-	 * Creates a e-mail message with the given subject and body. The sender is
-	 * taken from the value which was given to the constructor. The recipient
-	 * fields TO: and BCC: are generated in the follwing manner:
-	 * <ul>
-	 * <li>each ContactList-Name from the listOfContactLists is used as (empty
-	 * group) in the TO: field</li>
-	 * <li>all ContactList-Members are added to the BCC: field</li>
-	 * </ul>
-	 * 
-	 * @param listOfContactLists
-	 * @param subject
-	 * @param body
-	 * @return
-	 * @throws MessagingException
-	 * @throws AddressException
-	 * @throws MessagingException
-	 */
-	//fxdiff VCRP-16: intern mail system
-	public boolean sendEmail(MailContext context, List<ContactList> listOfContactLists, String subject, String body, List<File> attachments) throws AddressException, MessagingException {
-		body += footer;
-		MailerResult result = MailManager.getInstance().sendMessage(context, mailFromIdentity, mailfrom, null, null, null, null, listOfContactLists, null, subject, body, attachments);
-		return result.getReturnCode() == MailerResult.OK;
-	}
-	
-	//fxdiff VCRP-16: intern mail system
-	public boolean sendEmailCC(MailContext context, Identity cc, String subject, String body, List<File> attachments) throws AddressException, MessagingException {
-		MailerResult result = MailManager.getInstance().sendMessage(context, mailFromIdentity, mailfrom, null, null, cc, null, null, null, subject, body, attachments);
-		return result.getReturnCode() == MailerResult.OK;
-	}
-
-	/**
-	 * @param mailto
-	 * @param subject
-	 * @param body
-	 * @return
-	 * @throws AddressException
-	 * @throws SendFailedException
-	 * @throws MessagingException
-	 * TODO:gs handle exceptions internally and may return some error codes or so to get rid of dependecy of mail/activatoin jars in olat
-	 */
-	//fxdiff VCRP-16: intern mail system
-	public boolean sendEmail(String mailto, String subject, String body) throws AddressException, SendFailedException, MessagingException {
-		//OK context
-		body += footer;
-		//TO
-		MailerResult result = MailManager.getInstance().sendMessage(null, mailFromIdentity, mailfrom, null, mailto, null, null, null, null, subject, body, null);
-		return result.getReturnCode() == MailerResult.OK;
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/MailBoxExtension.java b/src/main/java/org/olat/core/util/mail/MailBoxExtension.java
index 2d0f3570d4ee7fcf03beb596d6da3f771cfc055d..816e04167459bc98c83bb63b292aa71fa3e4f443 100644
--- a/src/main/java/org/olat/core/util/mail/MailBoxExtension.java
+++ b/src/main/java/org/olat/core/util/mail/MailBoxExtension.java
@@ -38,7 +38,6 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.manager.BasicManager;
 import org.olat.core.util.StringHelper;
-import org.olat.core.util.mail.manager.MailManager;
 import org.olat.core.util.mail.model.DBMailLight;
 import org.olat.core.util.mail.ui.MailContextResolver;
 import org.olat.group.BusinessGroupService;
diff --git a/src/main/java/org/olat/core/util/mail/MailBundle.java b/src/main/java/org/olat/core/util/mail/MailBundle.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e6203e084c79bb6cf7903fc0483cbd7f2ce2101
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/MailBundle.java
@@ -0,0 +1,162 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util.mail;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 11.09.2013<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MailBundle {
+	
+	private MailContext context;
+	private Identity fromId;
+	private String from;
+	private Identity toId;
+	private String to;
+	private Identity cc;
+	private List<ContactList> contactLists; 
+	private String metaId;
+	private MailContent content;
+	
+	public MailContext getContext() {
+		return context;
+	}
+	
+	public void setContext(MailContext context) {
+		this.context = context;
+	}
+	
+	public Identity getFromId() {
+		return fromId;
+	}
+	
+	public void setFromId(Identity fromId) {
+		this.fromId = fromId;
+	}
+	
+	public String getFrom() {
+		return from;
+	}
+	
+	public void setFrom(String from) {
+		this.from = from;
+	}
+	
+	public Identity getToId() {
+		return toId;
+	}
+	
+	public void setToId(Identity toId) {
+		this.toId = toId;
+	}
+	
+	public String getTo() {
+		return to;
+	}
+	
+	public void setTo(String to) {
+		this.to = to;
+	}
+	
+	public Identity getCc() {
+		return cc;
+	}
+	
+	public void setCc(Identity cc) {
+		this.cc = cc;
+	}
+	
+	public List<ContactList> getContactLists() {
+		return contactLists;
+	}
+	
+	public void setContactList(ContactList list) {
+		this.contactLists = Collections.singletonList(list);
+	}
+	
+	public void setContactLists(List<ContactList> list) {
+		this.contactLists = list;
+	}
+	
+	public String getMetaId() {
+		return metaId;
+	}
+	
+	public void setMetaId(String metaId) {
+		this.metaId = metaId;
+	}
+	
+	public MailContent getContent() {
+		return content;
+	}
+	
+	public void setContent(MailContent content) {
+		this.content = content;
+	}
+	
+	public void setContent(String subject, String body, File... attachments) {
+		List<File> attachmentList = new ArrayList<File>();
+		if(attachments != null && attachments.length > 0) {
+			for(File attachment:attachments) {
+				if(attachment != null && attachment.exists()) {
+					attachmentList.add(attachment);
+				}
+			}
+		}
+		content = new SimpleContent(subject, body, attachmentList);
+	}
+
+	private static class SimpleContent implements MailContent {
+		
+		private String subject;
+		private String body;
+		private List<File> attachments;
+		
+		public SimpleContent(String subject, String body, List<File> attachments) {
+			this.subject = subject;
+			this.body = body;
+			this.attachments = attachments;
+		}
+
+		@Override
+		public String getSubject() {
+			return subject;
+		}
+
+		@Override
+		public String getBody() {
+			return body;
+		}
+
+		@Override
+		public List<File> getAttachments() {
+			return attachments;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/core/util/mail/MailContent.java b/src/main/java/org/olat/core/util/mail/MailContent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d26217964e1c27bbfcf51d75a3e6fe9cf1f6156
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/MailContent.java
@@ -0,0 +1,39 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util.mail;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * 
+ * Initial date: 11.09.2013<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface MailContent {
+	
+	public String getSubject();
+	
+	public String getBody();
+	
+	public List<File> getAttachments();
+
+}
diff --git a/src/main/java/org/olat/core/util/mail/MailHelper.java b/src/main/java/org/olat/core/util/mail/MailHelper.java
index cb000ccaa92937fee5dbffda13559a2f23f2a360..7b027cc0f6b3f35726a25f2ad95bc0a0bcb9e950 100644
--- a/src/main/java/org/olat/core/util/mail/MailHelper.java
+++ b/src/main/java/org/olat/core/util/mail/MailHelper.java
@@ -25,6 +25,7 @@
 */ 
 package org.olat.core.util.mail;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -36,10 +37,12 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
+import org.olat.core.id.Preferences;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
-import org.olat.core.util.ArrayHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.i18n.I18nModule;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -55,6 +58,26 @@ import org.olat.user.propertyhandlers.UserPropertyHandler;
  */
 public class MailHelper {
 	private static Map<String, Translator> translators = new HashMap<String, Translator>();
+	
+	
+	public static String getMailFooter(Locale locale) {
+		Translator trans = getTranslator(locale);
+		return trans.translate("footer.no.userdata", new String[] { Settings.getServerContextPathURI() });
+	}
+	
+	public static String getMailFooter(Identity sender) {
+		Preferences prefs = sender.getUser().getPreferences();
+		Locale locale = I18nManager.getInstance().getLocaleOrDefault(prefs.getLanguage());
+		return getMailFooter(locale, sender);
+	}
+	
+	public static String getMailFooter(MailBundle bundle) {
+		if(bundle.getFromId() instanceof Persistable) {
+			return getMailFooter(bundle.getFromId());
+		}
+		return getMailFooter(I18nModule.getDefaultLocale());
+	}
+	
 
 	/**
 	 * Create a mail footer for the given locale and sender.
@@ -81,22 +104,24 @@ public class MailHelper {
 		// username / server-url are always first [0], [1].		
 		UserManager um = UserManager.getInstance();
 		List<UserPropertyHandler> userPropertyHandlers = um.getUserPropertyHandlersFor(MailHelper.class.getCanonicalName(), false);
-		ArrayList<String> uProps = new ArrayList<String>(userPropertyHandlers.size()+2);
-		uProps.add(sender.getUser().getProperty(UserConstants.EMAIL, null));
-		uProps.add(Settings.getServerContextPathURI());
-		
+		List<String> userPropList = new ArrayList<String>(userPropertyHandlers.size()+2);
+		userPropList.add(sender.getUser().getProperty(UserConstants.EMAIL, null));
+		userPropList.add(Settings.getServerContextPathURI());
 		for (Iterator<UserPropertyHandler> iterator = userPropertyHandlers.iterator(); iterator.hasNext();) {
-			UserPropertyHandler handler = iterator.next();
-			uProps.add(handler.getUserProperty(user, locale));			
+			userPropList.add(iterator.next().getUserProperty(user, locale));
 		}
 		// add empty strings to prevent non-replaced wildcards like "{5}" etc. in emails.
-		while (uProps.size() < 15){
-			uProps.add("");
+		while (userPropList.size() < 15){
+			userPropList.add("");
 		}
 		
-		String[] userProps = new String[]{};
-		userProps = ArrayHelper.toArray(uProps);
-		return trans.translate("footer.with.userdata", userProps);
+		String[] userPropArr = userPropList.toArray(new String[userPropList.size()]);
+		for(int i=userPropArr.length; i-->0; ) {
+			if(userPropArr[i] == null) {
+				userPropArr[i] = "";
+			}
+		}
+		return trans.translate("footer.with.userdata", userPropArr);
 	}
 	
 	public static String getTitleForFailedUsersError(Locale locale) {
@@ -130,7 +155,7 @@ public class MailHelper {
 		synchronized (translators) {  //o_clusterok   brasato:::: nice idea, but move to translatorfactory and kick out translator.setLocale() (move it to LocaleChangableTranslator)
 			Translator trans = translators.get(ident);
 			if (trans == null) {
-				trans = Util.createPackageTranslator(Emailer.class, locale);
+				trans = Util.createPackageTranslator(MailHelper.class, locale);
 				translators.put(ident, trans);
 			}
 			return trans;
@@ -223,26 +248,32 @@ public class MailHelper {
 		return EmailAddressValidator.isValidEmailAddress(mailAddress);
 	}
 	
-	/**
-	 * check for disabled mail address
-	 * @param recipients
-	 * @param result
-	 * @return
-	 */
-	public static MailerResult removeDisabledMailAddress(List<Identity> identities, MailerResult result) {
-		String value = "";
-		if (identities != null) {
-			for (Identity identity : identities) {
-				value = identity.getUser().getProperty("emailDisabled", null);
-				if (value != null && value.equals("true")) {
-					result.addFailedIdentites(identity);
-					if(result.getReturnCode() != MailerResult.RECIPIENT_ADDRESS_ERROR) {
-						result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR);
-					}
+	public static boolean isDisabledMailAddress(Identity identity, MailerResult result) {
+		String value = identity.getUser().getProperty("emailDisabled", null);
+		if (value != null && value.equals("true")) {
+			if(result != null) {
+				result.addFailedIdentites(identity);
+				if(result.getReturnCode() != MailerResult.RECIPIENT_ADDRESS_ERROR) {
+					result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR);
+				}
+			}
+			return true;
+		}
+		return false;
+	}
+	
+	public static List<File> checkAttachments(File[] attachments, MailerResult result) {
+		List<File> attachmentList = new ArrayList<File>();
+		if(attachments != null) {
+			for(File attachment:attachments) {
+				if(attachment == null || !attachment.exists()) {
+					result.setReturnCode(MailerResult.ATTACHMENT_INVALID);
+				} else {
+					attachmentList.add(attachment);
 				}
 			}
 		}
-		return result;
+		return attachmentList;
 	}
 }
 
diff --git a/src/main/java/org/olat/core/util/mail/MailManager.java b/src/main/java/org/olat/core/util/mail/MailManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..95c9b8fbc85c8522694985adc7d619bd9ced25f1
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/MailManager.java
@@ -0,0 +1,162 @@
+package org.olat.core.util.mail;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.List;
+
+import javax.mail.Address;
+import javax.mail.internet.MimeMessage;
+
+import org.olat.core.id.Identity;
+import org.olat.core.util.mail.model.DBMail;
+import org.olat.core.util.mail.model.DBMailAttachment;
+import org.olat.core.util.mail.model.DBMailLight;
+import org.olat.core.util.notifications.PublisherData;
+import org.olat.core.util.notifications.Subscriber;
+import org.olat.core.util.notifications.SubscriptionContext;
+import org.olat.core.util.vfs.VFSLeaf;
+
+public interface MailManager {
+	
+
+	public SubscriptionContext getSubscriptionContext();
+	
+	public PublisherData getPublisherData();
+	
+	public Subscriber getSubscriber(Identity identity);
+	
+	/**
+	 * Subscribe to mail news
+	 * @param identity
+	 */
+	public void subscribe(Identity identity);
+	
+	
+	/**
+	 * @param key
+	 * @return The mail or null
+	 */
+	public DBMail getMessageByKey(Long key);
+	
+	public boolean hasNewMail(Identity identity);
+	
+	public VFSLeaf getAttachmentDatas(Long key);
+	
+	public VFSLeaf getAttachmentDatas(MailAttachment attachment);
+	
+	public List<DBMailAttachment> getAttachments(DBMailLight mail);
+	
+	public String saveAttachmentToStorage(String name, String mimetype, long checksum, long size, InputStream stream);
+
+	
+	/**
+	 * 
+	 * @param mail
+	 * @param read cannot be null
+	 * @param identity
+	 * @return true if the read flag has been changed
+	 */
+	public boolean setRead(DBMailLight mail, Boolean read, Identity identity);
+	
+	public DBMailLight toggleRead(DBMailLight mail, Identity identity);
+
+	/**
+	 * @param mail
+	 * @param marked cannot be null
+	 * @param identity
+	 * @return true if the marked flag has been changed
+	 */
+	public boolean setMarked(DBMailLight mail, Boolean marked, Identity identity);
+	
+	public DBMailLight toggleMarked(DBMailLight mail, Identity identity);
+	
+	/**
+	 * Set the mail as deleted for a user
+	 * @param mail
+	 * @param identity
+	 */
+	public void delete(DBMailLight mail, Identity identity, boolean deleteMetaMail);
+	
+	/**
+	 * Load all mails with the identity as from, mail which are not deleted
+	 * for this user. Recipients are loaded.
+	 * @param from
+	 * @param firstResult
+	 * @param maxResults
+	 * @return
+	 */
+	public List<DBMailLight> getOutbox(Identity from, int firstResult, int maxResults);
+	
+	public List<DBMailLight> getEmailsByMetaId(String metaId);
+	
+	/**
+	 * Load all mails with the identity as recipient, only mails which are not deleted
+	 * for this user. Recipients are NOT loaded if not explicitly wanted!
+	 * @param identity
+	 * @param unreadOnly
+	 * @param fetchRecipients
+	 * @param from
+	 * @param firstResult
+	 * @param maxResults
+	 * @return
+	 */
+	public List<DBMailLight> getInbox(Identity identity, Boolean unreadOnly, Boolean fetchRecipients, Date from, int firstResult, int maxResults);
+	
+	/**
+	 * Forward an E-Mail from the OpenOLAt mail box to the real one
+	 * @param identity
+	 * @param mail
+	 * @param result
+	 * @return
+	 */
+	public MailerResult forwardToRealInbox(Identity identity, DBMail mail, MailerResult result);
+	
+	public String getMailTemplate();
+	
+	public void setMailTemplate(String template);
+	
+	public String getDefaultMailTemplate();
+
+	
+	/**
+	 * Pack some standards inputs to separate MailBundle ready to be send
+	 * @param ctxt
+	 * @param recipientsTO
+	 * @param template
+	 * @param sender
+	 * @param metaId
+	 * @param result
+	 * @return
+	 */
+	public MailBundle[] makeMailBundles(MailContext ctxt, List<Identity> recipientsTO,
+			MailTemplate template, Identity sender, String metaId, MailerResult result);
+	
+	/**
+	 * 
+	 * @param ctxt
+	 * @param recipientTO
+	 * @param template
+	 * @param sender
+	 * @param metaId
+	 * @param result
+	 * @return
+	 */
+	public MailBundle makeMailBundle(MailContext ctxt, Identity recipientTO,
+			MailTemplate template, Identity sender, String metaId, MailerResult result);
+	
+	/**
+	 * Send the mail bundle
+	 * @param bundles
+	 * @return
+	 */
+	public MailerResult sendMessage(MailBundle... bundles);
+	
+	public MailerResult sendExternMessage(MailBundle bundle, MailerResult result);
+	
+	public MimeMessage createMimeMessage(Address from, Address[] tos, Address[] ccs, Address[] bccs, String subject, String body,
+			List<File> attachments, MailerResult result);
+	
+	public void sendMessage(MimeMessage msg, MailerResult result);
+
+}
diff --git a/src/main/java/org/olat/core/util/mail/MailPackage.java b/src/main/java/org/olat/core/util/mail/MailPackage.java
index d88f80083154f8588402f9bb75f94b874f3ffcd2..bfd2a80e620548cec14503c64b46dec750038c89 100644
--- a/src/main/java/org/olat/core/util/mail/MailPackage.java
+++ b/src/main/java/org/olat/core/util/mail/MailPackage.java
@@ -95,8 +95,9 @@ public class MailPackage {
 		return result;
 	}
 
-	
-	public void appendResult(MailerResult result) {
-		
+	public void appendResult(MailerResult newResult) {
+		if(result != null) {
+			result.append(newResult);
+		}
 	}
 }
diff --git a/src/main/java/org/olat/core/util/mail/MailerResult.java b/src/main/java/org/olat/core/util/mail/MailerResult.java
index bb88ac32752c5530cb239ee8aa986e9b737664f2..d0e92443a39e920d441e6a14575f4e4689a15359 100644
--- a/src/main/java/org/olat/core/util/mail/MailerResult.java
+++ b/src/main/java/org/olat/core/util/mail/MailerResult.java
@@ -49,7 +49,7 @@ public class MailerResult {
 	public static final int TEMPLATE_GENERAL_ERROR = 6;
 	public static final int ATTACHMENT_INVALID = 7;
 
-	private List<Identity> failedIdentites = new ArrayList<Identity>();
+	private final List<Identity> failedIdentites = new ArrayList<Identity>();
 	private int returnCode = OK;
 
 	/**
@@ -59,6 +59,10 @@ public class MailerResult {
 	public List<Identity> getFailedIdentites() {
 		return failedIdentites;
 	}
+	
+	public boolean isSuccessful() {
+		return getReturnCode() == MailerResult.OK;
+	}
 
 	/**
 	 * @return return code. If nothing else set return will be OK
@@ -86,6 +90,15 @@ public class MailerResult {
 		this.returnCode = returnCode;
 	}
 	
+	public void append(MailerResult newResult) {
+		if(newResult.getReturnCode() != MailerResult.OK) {
+			setReturnCode(newResult.getReturnCode());
+		}
+		if(newResult.getFailedIdentites() != null && newResult.getFailedIdentites().size() > 0) {
+			failedIdentites.addAll(newResult.getFailedIdentites());
+		}
+	}
+	
 	@Override
 	public String toString() {
 		StringBuilder sb = new StringBuilder();
diff --git a/src/main/java/org/olat/core/util/mail/MailerWithTemplate.java b/src/main/java/org/olat/core/util/mail/MailerWithTemplate.java
deleted file mode 100644
index c2ae87fe267bd8a0ce048324479a944ce29e14b6..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/mail/MailerWithTemplate.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.  
-* <p>
-*/ 
-package org.olat.core.util.mail;
-
-import java.io.File;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Properties;
-import java.util.UUID;
-
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.VelocityEngine;
-import org.apache.velocity.context.Context;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.olat.core.CoreSpringFactory;
-import org.olat.core.id.Identity;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
-import org.olat.core.util.i18n.I18nManager;
-import org.olat.core.util.mail.manager.MailManager;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * Description:<br>
- * Helper class for managing email templates
- * <P>
- * Initial Date: 21.11.2006 <br>
- * 
- * @author Florian Gnaegi, frentix GmbH<br>
- *         http://www.frentix.com
- */
-public class MailerWithTemplate {
-	private VelocityEngine velocityEngine;
-	
-	private static final OLog log = Tracing.createLoggerFor(MailerWithTemplate.class);
-	private static MailerWithTemplate INSTANCE = new MailerWithTemplate();
-	
-	@Autowired
-	private MailManager mailManager;
-
-	/**
-	 * Singleton constructor
-	 */
-	private MailerWithTemplate() {
-		INSTANCE = this;
-	}
-	
-	/**
-	 * @return MailerWithTemplate returns the singleton instance
-	 */
-	public static MailerWithTemplate getInstance() {
-		return INSTANCE;
-	}
-	
-	/**
-	 * [used by Spring]
-	 */
-	public void init() {
-		// init velocity engine
-		Properties p = null;
-		try {
-			velocityEngine = new VelocityEngine();
-			p = new Properties();
-			p.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
-			p.setProperty("runtime.log.logsystem.log4j.category", "syslog");
-			velocityEngine.init(p);
-		} catch (Exception e) {
-			throw new RuntimeException("config error " + p.toString());
-		}
-	}
-
-
-
-	/**
-	 * Send a mail to the given identity and the other recipients (CC and BCC)
-	 * using the template. The mail is sent as identity sender.
-	 * <p>
-	 * The method uses sendMailAsSeparateMails to send the message. If you have
-	 * multiple identities to which you need to send the same mail, use the
-	 * sendMailAsSeparateMails message and not this one
-	 * 
-	 * @param recipientTO Identity for TO. Must not be NULL
-	 * @param recipientsCC Identities List for CC. Can be NULL.
-	 * @param recipientsBCC Identities List for BCC. Can be NULL
-	 * @param template Mail template. Must not be NULL
-	 * @param sender The senders identity. Can be NULL. In case of NULL the
-	 *          systems send mail configuraton is used
-	 * @return MailerResult with status and list of identites that could not be
-	 *         mailed to
-	 */
-	//fxdiff VCRP-16: intern mail system
-	public MailerResult sendRealMail(Identity recipientTO, MailTemplate template) {
-		MailerResult result = new MailerResult();
-		VelocityContext context = new VelocityContext();
-		MessageContent msg = createWithContext(context, recipientTO, template, null, result);
-		if(result.getReturnCode() != MailerResult.OK) {
-			return result;
-		}
-
-		mailManager.sendExternMessage(null, null, recipientTO, null, null, null, null, msg.getSubject(), msg.getBody(), null, result);
-		return result;
-	}
-
-	/**
-	 * Send a mail to the given identities (TO, CC and BCC) using the template.
-	 * The mail is sent as identity sender.
-	 * <p>
-	 * The template is parsed for every identity in the TO list. For each of those
-	 * identities a separate mail is sent. Use this only if the mail content
-	 * differ for each identity. Otherwise use the sendMailAsOneMail method.
-	 * <p>
-	 * In this method the recipients will not know who else got the mail since the
-	 * mail is addressed personally.
-	 * 
-	 * @param mCtxt The mail contact (optional)
-	 * @param recipientsTO Identities List for TO. Must not be NULL and contain at
-	 *          least one identity.
-	 * @param recipientsCC Identities List for CC. Can be NULL.
-	 * @param recipientsBCC Identities List for BCC. Can be NULL
-	 * @param template Mail template. Must not be NULL
-	 * @param sender The senders identity. Can be NULL. In case of NULL the
-	 *          systems send mail configuraton is used
-	 * @return MailerResult with status and list of identites that could not be
-	 *         mailed to
-	 */
-	public MailerResult sendMailAsSeparateMails(MailContext mCtxt, List<Identity> recipientsTO, List<Identity> recipientsCC,
-			MailTemplate template, Identity sender) {
-		return sendMailAsSeparateMails(mCtxt, recipientsTO, recipientsCC, template, sender, null);
-	}
-	
-	public MailerResult sendMailAsSeparateMails(MailContext mCtxt, List<Identity> recipientsTO, List<Identity> recipientsCC,
-			MailTemplate template, Identity sender, String uuid) {
-		
-		String metaId = uuid == null ? UUID.randomUUID().toString().replace("-", "") : uuid;
-		MailerResult result = new MailerResult();
-		if (CoreSpringFactory.getImpl(MailModule.class).getMailhost() == null) {
-			result.setReturnCode(MailerResult.MAILHOST_UNDEFINED);
-			return result;
-		}
-		boolean isMailSendToRecipient = false;
-		if (recipientsTO != null) {
-			for (Identity recipient : recipientsTO) {
-				// populate velocity context with variables
-				VelocityContext context = getContext(template);
-				template.putVariablesInMailContext(context, recipient);
-				sendWithContext(context, mCtxt, metaId, recipient, template, sender, result);
-				if (!result.getFailedIdentites().contains(recipient)) {
-					isMailSendToRecipient = true;
-				}
-			}
-		}
-		if (recipientsCC != null) {
-			for (Identity recipient : recipientsCC) {
-				List<Identity> cc = new ArrayList<Identity>();
-				cc.add(recipient);
-				// populate velocity context with variables
-				VelocityContext context = getContext(template);
-				template.putVariablesInMailContext(context, recipient);
-				sendWithContext(context, mCtxt, metaId, recipient, template, sender, result);
-			}
-		}
-		if(!isMailSendToRecipient) {
-			result.setReturnCode(MailerResult.RECIPIENT_ADDRESS_ERROR);
-		}//only one successful to is needed to return OK
-		else if(isMailSendToRecipient && result.getReturnCode() == MailerResult.RECIPIENT_ADDRESS_ERROR) {
-			result.setReturnCode(MailerResult.OK);
-		}
-		return result;
-	}
-	
-	private VelocityContext getContext(MailTemplate template) {
-		if(template != null && template.getContext() != null) {
-			return new VelocityContext(template.getContext());
-		}
-		return new VelocityContext();
-	}
-	
-	/**
-	 * may return null, but then the result.getReturnCode != OK... so check the
-	 * result code.
-	 * @param context
-	 * @param recipientTO
-	 * @param recipientsCC
-	 * @param recipientsBCC
-	 * @param template
-	 * @param sender
-	 * @param result
-	 * @return
-	 */
-	//fxdiff VCRP-16: intern mail system
-	private MessageContent createWithContext(VelocityContext context, Identity recipientTO,
-			MailTemplate template, Identity sender, MailerResult result){
-
-		// merge subject template with context variables
-		StringWriter subjectWriter = new StringWriter();
-		evaluate(context, template.getSubjectTemplate(), subjectWriter, result);
-		// merge body template with context variables
-		StringWriter bodyWriter = new StringWriter();
-		evaluate(context, template.getBodyTemplate(), bodyWriter, result);
-		// check for errors - exit
-		if (result.getReturnCode() != MailerResult.OK) return null;
-	
-		Locale recLocale = Locale.getDefault();
-		if(recipientTO != null){
-			recLocale = I18nManager.getInstance().getLocaleOrDefault(recipientTO.getUser().getPreferences().getLanguage());
-		}
-		String subject = subjectWriter.toString();
-		String body = bodyWriter.toString() + MailHelper.getMailFooter(recLocale, sender) + "\n";
-
-		// create mime message
-		return new MessageContent(subject, body);
-		
-	}
-	
-	private class MessageContent {
-		private final String subject;
-		private final String body;
-		
-		public MessageContent(String subject, String body) {
-			this.subject = subject;
-			this.body = body;
-		}
-
-		public String getSubject() {
-			return subject;
-		}
-
-		public String getBody() {
-			return body;
-		}
-	}
-	
-	/**
-	 * Helper method to send email with given velocity-context.
-	 * @param context
-	 * @param recipientTO
-	 * @param recipientsCC
-	 * @param recipientsBCC
-	 * @param template
-	 * @param sender
-	 * @param result
-	 */
-	//fxdiff VCRP-16: intern mail system
-	private void sendWithContext(VelocityContext context, MailContext mCtxt, String metaId, Identity recipientTO,
-			MailTemplate template, Identity sender, MailerResult result) {	
-		
-		List<Identity> identityTO = new ArrayList<Identity>();
-		if(recipientTO != null) {
-			identityTO.add(recipientTO);
-		}
-		List<Identity> failedIdentitiesTO = new ArrayList<Identity>();
-		int sizeFailedIdentities = result.getFailedIdentites().size();
-		result = MailHelper.removeDisabledMailAddress(identityTO, result);
-		failedIdentitiesTO.addAll(result.getFailedIdentites());
-		if(failedIdentitiesTO.size() == sizeFailedIdentities) {
-			if(identityTO.size()>0) recipientTO = identityTO.get(0);
-		} else {
-			recipientTO = null;
-		}
-
-		MessageContent msg = createWithContext(context, recipientTO, template, sender, result);
-		if(msg != null && result.getReturnCode() == MailerResult.OK){
-			// send mail
-			List<File> attachmentList = new ArrayList<File>();
-			File[] attachments = template.getAttachments();
-			if(attachments != null) {
-				for(File attachment:attachments) {
-					if(attachment == null || !attachment.exists()) {
-						result.setReturnCode(MailerResult.ATTACHMENT_INVALID);
-					} else {
-						attachmentList.add(attachment);
-					}
-				}
-			}
-
-			MailerResult mgrResult = mailManager.sendMessage(mCtxt, sender, null, recipientTO, null, null, null, null,
-					metaId, msg.getSubject(), msg.getBody(), attachmentList);
-			
-			if(mgrResult.getReturnCode() != MailerResult.OK) {
-				result.setReturnCode(mgrResult.getReturnCode());
-			}
-			if(mgrResult.getFailedIdentites() != null) {
-				for(Identity failedIdentity:mgrResult.getFailedIdentites()) {
-					result.addFailedIdentites(failedIdentity);
-				}
-			}
-			
-		}
-	}
-
-	/**
-	 * Internal Helper: merges a velocity context with a template.
-	 * 
-	 * @param context
-	 * @param template
-	 * @param writer writer that contains merged result
-	 * @param mailerResult
-	 */
-	protected final void evaluate(Context context, String template, StringWriter writer, MailerResult mailerResult) {
-		try {
-			boolean result = velocityEngine.evaluate(context, writer, "mailTemplate", template);
-			if (result) {
-				mailerResult.setReturnCode(MailerResult.OK);
-			} else {
-				log.warn("can't send email from user template with no reason");
-				mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
-			}
-		} catch (ParseErrorException e) {
-			log.warn("can't send email from user template", e);
-			mailerResult.setReturnCode(MailerResult.TEMPLATE_PARSE_ERROR);
-		} catch (MethodInvocationException e) {
-			log.warn("can't send email from user template", e);
-			mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
-		} catch (ResourceNotFoundException e) {
-			log.warn("can't send email from user template", e);
-			mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
-		} catch (Exception e) {
-			log.warn("can't send email from user template", e);
-			mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/_chelp/mail-admin-template.html b/src/main/java/org/olat/core/util/mail/_chelp/mail-admin-template.html
new file mode 100644
index 0000000000000000000000000000000000000000..6eb72de9f49b64a93eda9bac65aaa05348dc6c3a
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/_chelp/mail-admin-template.html
@@ -0,0 +1 @@
+$r.translate("chelp.customizeMailTemplate1")
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/_content/mail_template.html b/src/main/java/org/olat/core/util/mail/_content/mail_template.html
new file mode 100644
index 0000000000000000000000000000000000000000..569897a71d49f6da3a3def47ba9a565b713a4274
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/_content/mail_template.html
@@ -0,0 +1,4 @@
+<body>
+	<p>$content</p>
+	<p>$footer</p>
+</body>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties
index ccf8aa1872833a9223200db368439487c46bbad1..056eecbfc46b8c9c67facc0f124f89fa5c60c7fc 100644
--- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_de.properties
@@ -1,11 +1,13 @@
 #Mon Mar 02 09:54:04 CET 2009
 chelp.mail-templ.title=$\:mailnotification.title
+chelp.mail-admin-template.title=Infos zur E-Mail template
 chelp.sendMail1=W\u00E4hlen Sie hier, ob die Benutzer, die Sie eintragen, austragen oder verschieben ein Mail erhalten sollen.
 chelp.sendMail2 =Ist diese Option aktiviert, wird Ihnen eine Kopie dieser E-Mail an Ihre in OLAT eingetragene E-Mail-Adresse gesendet.
 chelp.sendMail5=Sie k\u00F6nnen die folgenden Variablen verwenden\:
 chelp.sendMail6=Name der Gruppe
 chelp.sendMail7=Beschreibung der Gruppe
 chelp.sendMail8=Liste der Kurse, in denen die Gruppe verwendet wird.
+chelp.customizeMailTemplate1=Sie k\u00F6nnen die E-Mail template anpassen.
 contact.cp.from = Kopie an Absender
 add.email=Hinzufügen
 footer.no.userdata=\n\n--- \nDiese Nachricht wurde automatisch von der Lernplattform OpenOLAT versandt.\n{0}
@@ -42,6 +44,10 @@ mail.admin.intern.enabled=OLAT Postfach aktivieren
 mail.admin.default.settings=Standardeinstellung für E-Mail Versand
 mail.admin.intern.only=E-Mails an das interne OLAT Postfach zustellen
 mail.admin.intern.real.mail=E-Mails an das interne OLAT Postfach und die persönliche E-Mail Adresse zustellen
+mail.settings=Einstellungen
+mail.template=Template
+mail.template.title=Standard Mailtemplate
+mail.template.description=Hier können Sie die Mailtemplate anpassen.
 mail.attachments=Anhang
 mail.confirm.delete.title=E-Mails l\u00F6schen
 mail.confirm.delete.multi.text=Bitte bestätigen Sie, dass Sie die selektierten {0} E-Mails inklusive aller Anhänge unwiderruflich l\u00F6schen wollen:
diff --git a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties
index d2c953f5c3df7ba983a11a2383f114202c3a5542..1bb9d224c139f81c64f698db21aa473feb8aafd7 100644
--- a/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/core/util/mail/_i18n/LocalStrings_en.properties
@@ -2,6 +2,7 @@
 add.email=Add
 chelp.mail-admin.title=$\:mail.admin.title
 chelp.mail-templ.title=E-mail notification
+chelp.mail-admin-template.title=Infos about E-Mail template
 chelp.mail.module=OLAT has an internal e-mail inbox system that lists all sent and received e-mails of each user in his personal home area. The OLAT e-mail inbox system is an optional component.
 chelp.mail.module.extern=If the OLAT inbox system is enabled, all received and sent emails will be listed in the users personal inbox.
 chelp.mail.module.extern.config=In addition, each user can configure in his preferences wether he wants to receive mails from OLAT to his personal e-mail address or if he prefers to read the mail within OLAT. As administrator you can define the default behavior.
@@ -14,6 +15,7 @@ chelp.sendMail5=You can use the following variables\:
 chelp.sendMail6=Name of group
 chelp.sendMail7=Description of group
 chelp.sendMail8=List of courses in which this group is used.
+chelp.customizeMailTemplate1=You can customize your E-Mail template.
 contact.cp.from=Copy sent to addresser
 footer.no.userdata=\n\n--- \nThis message has been sent automatically via the learning platform OpenOLAT.\r\n{0}
 footer.with.userdata=\n\n--- \n{2} {3} ({0})\r\n{4} {5}\r\n\r\nThis message has been sent via the learning platform OpenOLAT.\r\n{1}
@@ -32,6 +34,10 @@ mail.admin.intern.enabled=Enable your OLAT e-mail inbox
 mail.admin.intern.only=Send e-mails to the internal OLAT inbox
 mail.admin.intern.real.mail=Send e-Mails to the internal OLAT inbox and the personal e-mail address
 mail.admin.title=E-mail inbox and outbox
+mail.settings=Settings
+mail.template=Template
+mail.template.title=Standard E-Mail Template
+mail.template.description=You customize the E-Mail template here.
 mail.attachments=Attachment
 mail.body=Message
 mail.confirm.delete.multi.text=Please confirm that you want to delete the selected {0} e-mails including their attachments. This can not be undone.
diff --git a/src/main/java/org/olat/core/util/mail/_spring/mailContext.xml b/src/main/java/org/olat/core/util/mail/_spring/mailContext.xml
index adc365a7fb1fb37f57c377de3caaa2dc67e2855b..2aa9bbbcfc9e1fdf8122f548d4903368d452a150 100644
--- a/src/main/java/org/olat/core/util/mail/_spring/mailContext.xml
+++ b/src/main/java/org/olat/core/util/mail/_spring/mailContext.xml
@@ -54,11 +54,7 @@
 		<property name="parentTreeNodeIdentifier" value="sysconfigParent" /> 
 	</bean> 
 	
-	<bean id="mailerWithTemplate" class="org.olat.core.util.mail.MailerWithTemplate" init-method="init">
-	
-	</bean>
-	
-	<bean id="mailManager" class="org.olat.core.util.mail.manager.MailManager" init-method="init">
+	<bean id="mailManager" class="org.olat.core.util.mail.manager.MailManagerImpl" init-method="init">
 		<constructor-arg index="0" ref="mailModule" />
 		<property name="dbInstance" ref="database"/>
 		<property name="notificationsManager" ref="org.olat.core.util.notifications.NotificationsManager"/>
diff --git a/src/main/java/org/olat/core/util/mail/manager/MailManager.java b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
similarity index 78%
rename from src/main/java/org/olat/core/util/mail/manager/MailManager.java
rename to src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
index 3980db0290f9207d74576352514176328060f548..3a7952f128dbdadacb400e78eb21902736c3bfb7 100644
--- a/src/main/java/org/olat/core/util/mail/manager/MailManager.java
+++ b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
@@ -23,9 +23,12 @@ package org.olat.core.util.mail.manager;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -57,6 +60,13 @@ import javax.persistence.TypedQuery;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.RuntimeConstants;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.PersistentObject;
 import org.olat.core.helpers.Settings;
@@ -67,10 +77,16 @@ import org.olat.core.manager.BasicManager;
 import org.olat.core.util.Encoder;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.WebappHelper;
+import org.olat.core.util.filter.impl.NekoHTMLFilter;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.MailAttachment;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailContent;
 import org.olat.core.util.mail.MailContext;
+import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailModule;
+import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
 import org.olat.core.util.mail.MailerSMTPAuthenticator;
 import org.olat.core.util.mail.model.DBMail;
@@ -101,24 +117,21 @@ import org.olat.core.util.vfs.VFSManager;
  * Initial Date:  24 mars 2011 <br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class MailManager extends BasicManager {
+public class MailManagerImpl extends BasicManager implements MailManager {
+
+	public static final String MAIL_TEMPLATE_FOLDER = "/customizing/mail/";
+	
+	private VelocityEngine velocityEngine;
 	
 	private final MailModule mailModule;
 	private DB dbInstance;
 	private FileStorage attachmentStorage;
 	private NotificationsManager notificationsManager;
 	
-	private static MailManager INSTANCE;
-	
-	public MailManager(MailModule mailModule) {
-		INSTANCE = this;
+	public MailManagerImpl(MailModule mailModule) {
 		this.mailModule = mailModule;
 	}
 	
-	public static MailManager getInstance() {
-		return INSTANCE;
-	}
-
 	/**
 	 * [used by Spring]
 	 * 
@@ -146,19 +159,33 @@ public class MailManager extends BasicManager {
 		PublisherData pdata = getPublisherData();
 		SubscriptionContext scontext = getSubscriptionContext();
 		notificationsManager.getOrCreatePublisher(scontext, pdata);
+		
+		Properties p = null;
+		try {
+			velocityEngine = new VelocityEngine();
+			p = new Properties();
+			p.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
+			p.setProperty("runtime.log.logsystem.log4j.category", "syslog");
+			velocityEngine.init(p);
+		} catch (Exception e) {
+			throw new RuntimeException("config error " + p.toString());
+		}
 	}
 	
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return new SubscriptionContext("Inbox", 0l, "");
 	}
-	
+
+	@Override
 	public PublisherData getPublisherData() {
 		String data = "";
 		String businessPath = "[Inbox:0]";
 		PublisherData publisherData = new PublisherData("Inbox", data, businessPath);
 		return publisherData;
 	}
-	
+
+	@Override
 	public Subscriber getSubscriber(Identity identity) {
 		SubscriptionContext context = getSubscriptionContext();
 		if(context == null) return null;
@@ -168,7 +195,8 @@ public class MailManager extends BasicManager {
 		}
 		return notificationsManager.getSubscriber(identity, publisher);
 	}
-	
+
+	@Override
 	public void subscribe(Identity identity) {
 		PublisherData data = getPublisherData();
 		SubscriptionContext context = getSubscriptionContext();
@@ -177,6 +205,7 @@ public class MailManager extends BasicManager {
 		}
 	}
 
+	@Override
 	public DBMail getMessageByKey(Long key) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select mail from ").append(DBMailImpl.class.getName()).append(" mail")
@@ -190,7 +219,8 @@ public class MailManager extends BasicManager {
 		if(mails.isEmpty()) return null;
 		return mails.get(0);
 	}
-	
+
+	@Override
 	public List<DBMailAttachment> getAttachments(DBMailLight mail) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select attachment from ").append(DBMailAttachment.class.getName()).append(" attachment")
@@ -203,7 +233,7 @@ public class MailManager extends BasicManager {
 				.getResultList();
 	}
 	
-	public DBMailAttachment getAttachment(Long key) {
+	private DBMailAttachment getAttachment(Long key) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select attachment from ").append(DBMailAttachment.class.getName()).append(" attachment")
 			.append(" where attachment.key=:attachmentKey");
@@ -218,7 +248,8 @@ public class MailManager extends BasicManager {
 		}
 		return attachments.get(0);
 	}
-	
+
+	@Override
 	public String saveAttachmentToStorage(String name, String mimetype, long checksum, long size, InputStream stream) {
 		String hasSibling = getAttachmentSibling(name, mimetype, checksum, size);
 		if(StringHelper.containsNonWhitespace(hasSibling)) {
@@ -234,7 +265,7 @@ public class MailManager extends BasicManager {
 		return dir + uniqueName;
 	}
 	
-	public String getAttachmentSibling(String name, String mimetype, long checksum, long size) {
+	private String getAttachmentSibling(String name, String mimetype, long checksum, long size) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select attachment from ").append(DBMailAttachment.class.getName()).append(" attachment")
 			.append(" where attachment.checksum=:checksum and attachment.size=:size and attachment.name=:name");
@@ -260,7 +291,7 @@ public class MailManager extends BasicManager {
 		return attachments.get(0).getPath();
 	}
 	
-	public int countAttachment(String path) {
+	private int countAttachment(String path) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select count(attachment) from ").append(DBMailAttachment.class.getName()).append(" attachment")
 			.append(" where attachment.path=:path");
@@ -270,12 +301,14 @@ public class MailManager extends BasicManager {
 				.setParameter("path", path)
 				.getSingleResult().intValue();
 	}
-	
+
+	@Override
 	public VFSLeaf getAttachmentDatas(Long key) {
 		DBMailAttachment attachment = getAttachment(key);
 		return getAttachmentDatas(attachment);
 	}
-	
+
+	@Override
 	public VFSLeaf getAttachmentDatas(MailAttachment attachment) {
 		String path = attachment.getPath();
 		if(StringHelper.containsNonWhitespace(path)) {
@@ -287,7 +320,8 @@ public class MailManager extends BasicManager {
 		}
 		return null;
 	}
-	
+
+	@Override
 	public boolean hasNewMail(Identity identity) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select count(mail) from ").append(DBMailImpl.class.getName()).append(" mail")
@@ -308,6 +342,7 @@ public class MailManager extends BasicManager {
 	 * @param identity
 	 * @return true if the read flag has been changed
 	 */
+	@Override
 	public boolean setRead(DBMailLight mail, Boolean read, Identity identity) {
 		if(mail == null || read == null || identity == null) throw new NullPointerException();
 		
@@ -324,7 +359,8 @@ public class MailManager extends BasicManager {
 		}
 		return changed;
 	}
-	
+
+	@Override
 	public DBMailLight toggleRead(DBMailLight mail, Identity identity) {
 		Boolean read = null;
 		for(DBMailRecipient recipient:mail.getRecipients()) {
@@ -346,6 +382,7 @@ public class MailManager extends BasicManager {
 	 * @param identity
 	 * @return true if the marked flag has been changed
 	 */
+	@Override
 	public boolean setMarked(DBMailLight mail, Boolean marked, Identity identity) {
 		if(mail == null || marked == null || identity == null) throw new NullPointerException();
 
@@ -365,7 +402,8 @@ public class MailManager extends BasicManager {
 		}
 		return changed;
 	}
-	
+
+	@Override
 	public DBMailLight toggleMarked(DBMailLight mail, Identity identity) {
 		Boolean marked = null;
 		for(DBMailRecipient recipient:mail.getRecipients()) {
@@ -386,6 +424,7 @@ public class MailManager extends BasicManager {
 	 * @param mail
 	 * @param identity
 	 */
+	@Override
 	public void delete(DBMailLight mail, Identity identity, boolean deleteMetaMail) {
 		if(StringHelper.containsNonWhitespace(mail.getMetaId()) && deleteMetaMail) {
 			List<DBMailLight> mails = getEmailsByMetaId(mail.getMetaId());
@@ -467,6 +506,7 @@ public class MailManager extends BasicManager {
 	 * @param maxResults
 	 * @return
 	 */
+	@Override
 	public List<DBMailLight> getOutbox(Identity from, int firstResult, int maxResults) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select distinct(mail) from ").append(DBMailLightImpl.class.getName()).append(" mail")
@@ -489,7 +529,8 @@ public class MailManager extends BasicManager {
 		List<DBMailLight> mails = query.getResultList();
 		return mails;
 	}
-	
+
+	@Override
 	public List<DBMailLight> getEmailsByMetaId(String metaId) {
 		if(!StringHelper.containsNonWhitespace(metaId)) return Collections.emptyList();
 		
@@ -515,6 +556,7 @@ public class MailManager extends BasicManager {
 	 * @param maxResults
 	 * @return
 	 */
+	@Override
 	public List<DBMailLight> getInbox(Identity identity, Boolean unreadOnly, Boolean fetchRecipients, Date from, int firstResult, int maxResults) {
 		StringBuilder sb = new StringBuilder();
 		String fetchOption = (fetchRecipients != null && fetchRecipients.booleanValue()) ? "fetch" : "";
@@ -546,21 +588,246 @@ public class MailManager extends BasicManager {
 		List<DBMailLight> mails = query.getResultList();
 		return mails;
 	}
+
+	@Override
+	public String getMailTemplate() {
+		File baseFolder = new File(WebappHelper.getUserDataRoot(), MAIL_TEMPLATE_FOLDER);	
+		File template = new File(baseFolder, "mail_template.html");
+		if(template.exists()) {
+			InputStream in = null;
+			try {
+				in = new FileInputStream(template);
+				return IOUtils.toString(in);
+			} catch (IOException e) {
+				logError("", e);
+			} finally {
+				IOUtils.closeQuietly(in);
+			}
+		}
+		return getDefaultMailTemplate();
+	}
+
+	@Override
+	public void setMailTemplate(String template) {
+		File baseFolder = new File(WebappHelper.getUserDataRoot(), MAIL_TEMPLATE_FOLDER);
+		if(!baseFolder.exists()) {
+			baseFolder.mkdirs();
+		}
+		OutputStream out = null;
+		try {
+			File templateFile = new File(baseFolder, "mail_template.html");
+			StringReader reader = new StringReader(template);
+			out = new FileOutputStream(templateFile);
+			IOUtils.copy(reader, out);
+		} catch (IOException e) {
+			logError("", e);
+		} finally {
+			IOUtils.closeQuietly(out);
+		}
+	}
+
+	@Override
+	public String getDefaultMailTemplate() {
+		try {
+			InputStream in = MailModule.class.getResourceAsStream("_content/mail_template.html");
+			return IOUtils.toString(in);
+		} catch (IOException e) {
+			logError("Cannot read the default mail template", e);
+			return null;
+		}
+	}
+
+	@Override
+	public MailBundle[] makeMailBundles(MailContext ctxt, List<Identity> recipientsTO,
+			MailTemplate template, Identity sender, String metaId, MailerResult result) {
+		List<MailBundle> bundles = new ArrayList<MailBundle>();
+		if(recipientsTO != null) {
+			for(Identity recipient: recipientsTO) {
+				MailBundle bundle =  makeMailBundle(ctxt, recipient, template, sender, metaId, result);
+				if(bundle != null) {
+					bundles.add(bundle);
+				}
+			}
+		}
+
+		return bundles.toArray(new MailBundle[bundles.size()]);
+	}
+
+	@Override
+	public MailBundle makeMailBundle(MailContext ctxt, Identity recipientTO,
+			MailTemplate template, Identity sender, String metaId, MailerResult result) {	
+
+		MailBundle bundle;
+		if(MailHelper.isDisabledMailAddress(recipientTO, result)) {
+			bundle = null;//email disabled, nothing to do
+		} else {
+			MailContent msg = createWithContext(recipientTO, template, result);
+			if(msg != null && result.getReturnCode() == MailerResult.OK){
+				// send mail
+				bundle = new MailBundle();
+				bundle.setContext(ctxt);
+				bundle.setFromId(sender);
+				bundle.setToId(recipientTO);
+				bundle.setMetaId(metaId);
+				bundle.setContent(msg);
+			} else {
+				bundle = null;
+			}
+		}
+		return bundle;
+	}
+
+	@Override
+	public MailerResult sendMessage(MailBundle... bundles) {
+		MailerResult result = new MailerResult();
+		for(MailBundle bundle:bundles) {
+			MailContent content = decorateMail(bundle);
+			if(mailModule.isInternSystem()) {
+				saveDBMessage(bundle.getContext(), bundle.getFromId(), bundle.getFrom(),
+						bundle.getToId(), bundle.getTo(), bundle.getCc(),
+						bundle.getContactLists(), bundle.getMetaId(), content, result);
+			} else {
+				sendExternMessage(bundle.getFromId(), bundle.getFrom(),
+						bundle.getToId(), bundle.getTo(), bundle.getCc(),
+						bundle.getContactLists(), content, result);
+			}
+		}
+		return result;
+	}
 	
-	public MailerResult sendMessage(MailContext context, Identity fromId, String from, Identity toId, String to,
-			Identity cc, List<ContactList> ccLists, List<ContactList> bccLists, 
-			String metaId, String subject, String body, List<File> attachments) {
-		
+	protected MailContent decorateMail(MailBundle bundle) {
+		MailContent content = bundle.getContent();
+
+		String template = getMailTemplate();
+		boolean htmlTemplate = containsHtml(template);
+		String body = content.getBody();
+		boolean htmlContent =  containsHtml(body);
+		if(htmlTemplate && !htmlContent) {
+			body = body.replace("\n", "<br />");
+		}
+		VelocityContext context = new VelocityContext();
+		context.put("content", body);
+		context.put("footer", MailHelper.getMailFooter(bundle));
+		context.put("server", Settings.getServerContextPathURI());
+
+		StringWriter writer = new StringWriter(2000);
 		MailerResult result = new MailerResult();
-		if(mailModule.isInternSystem()) {
-			saveDBMessage(context, fromId, from, toId, to, cc, ccLists, bccLists, metaId, subject, body, attachments, result);
+		evaluate(context, template, writer, result);
+		
+		String decoratedBody;
+		if(result.isSuccessful()) {
+			decoratedBody = writer.toString();
 		} else {
-			sendExternMessage(fromId, from, toId, to, cc, ccLists, bccLists, subject, body, attachments, result);
+			decoratedBody = content.getBody();
 		}
-		return result;
+		return new MessageContent(content.getSubject(), decoratedBody, content.getAttachments());
 	}
 	
+	protected MailContent createWithContext(Identity recipient, MailTemplate template, MailerResult result) {
+		VelocityContext context;
+		if(template != null && template.getContext() != null) {
+			context = new VelocityContext(template.getContext());
+		} else {
+			context = new VelocityContext();
+		}
+		template.putVariablesInMailContext(context, recipient);
+
+		// merge subject template with context variables
+		StringWriter subjectWriter = new StringWriter();
+		evaluate(context, template.getSubjectTemplate(), subjectWriter, result);
+		// merge body template with context variables
+		StringWriter bodyWriter = new StringWriter();
+		evaluate(context, template.getBodyTemplate(), bodyWriter, result);
+		// check for errors - exit
+		if (result.getReturnCode() != MailerResult.OK) {
+			return null;
+		}
+		
+		String subject = subjectWriter.toString();
+		String body = bodyWriter.toString();
+		List<File> checkedFiles = MailHelper.checkAttachments(template.getAttachments(), result);
+		File[] attachments = checkedFiles.toArray(new File[checkedFiles.size()]);
+		return new MessageContent(subject, body, attachments);
+	}
 	
+	/**
+	 * Internal Helper: merges a velocity context with a template.
+	 * 
+	 * @param context
+	 * @param template
+	 * @param writer writer that contains merged result
+	 * @param mailerResult
+	 */
+	protected void evaluate(Context context, String template, StringWriter writer, MailerResult mailerResult) {
+		try {
+			boolean result = velocityEngine.evaluate(context, writer, "mailTemplate", template);
+			if (result) {
+				mailerResult.setReturnCode(MailerResult.OK);
+			} else {
+				logWarn("can't send email from user template with no reason", null);
+				mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
+			}
+		} catch (ParseErrorException e) {
+			logWarn("can't send email from user template", e);
+			mailerResult.setReturnCode(MailerResult.TEMPLATE_PARSE_ERROR);
+		} catch (MethodInvocationException e) {
+			logWarn("can't send email from user template", e);
+			mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
+		} catch (ResourceNotFoundException e) {
+			logWarn("can't send email from user template", e);
+			mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
+		} catch (Exception e) {
+			logWarn("can't send email from user template", e);
+			mailerResult.setReturnCode(MailerResult.TEMPLATE_GENERAL_ERROR);
+		}
+	}
+	
+	private static class MessageContent implements MailContent {
+		private final String subject;
+		private final String body;
+		private final List<File> attachments;
+		
+		public MessageContent(String subject, String body, File[] attachmentArr) {
+			this.subject = subject;
+			this.body = body;
+			
+			attachments = new ArrayList<File>();
+			if(attachmentArr != null && attachmentArr.length > 0) {
+				for(File attachment:attachmentArr) {
+					if(attachment != null && attachment.exists()) {
+						attachments.add(attachment);
+					}
+				}
+			}
+		}
+		
+		public MessageContent(String subject, String body, List<File> attachmentList) {
+			this.subject = subject;
+			this.body = body;
+			if(attachmentList == null) {
+				this.attachments = new ArrayList<File>(1);
+			} else {
+				this.attachments = new ArrayList<File>(attachmentList);
+			}
+		}
+
+		@Override
+		public String getSubject() {
+			return subject;
+		}
+
+		@Override
+		public String getBody() {
+			return body;
+		}
+
+		@Override
+		public List<File> getAttachments() {
+			return attachments;
+		}
+	}
+
+	@Override
 	public MailerResult forwardToRealInbox(Identity identity, DBMail mail, MailerResult result) {
 		
 		if(result == null) {
@@ -582,6 +849,12 @@ public class MailManager extends BasicManager {
 		return result;
 	}
 	
+	@Override
+	public MailerResult sendExternMessage(MailBundle bundle, MailerResult result) {
+		return sendExternMessage(bundle.getFromId(), bundle.getFrom(), bundle.getToId(), bundle.getTo(), bundle.getCc(), bundle.getContactLists(),
+				bundle.getContent(), result);
+	}
+	
 	
 	/**
 	 * Send the message via e-mail, always.
@@ -595,13 +868,13 @@ public class MailManager extends BasicManager {
 	 * @param attachments
 	 * @return
 	 */
-	public MailerResult sendExternMessage(Identity fromId, String from, Identity toId, String to, Identity cc, List<ContactList> ccLists, List<ContactList> bccLists,
-			String subject, String body, List<File> attachments, MailerResult result) {
+	private MailerResult sendExternMessage(Identity fromId, String from, Identity toId, String to, Identity cc, List<ContactList> bccLists,
+			MailContent content, MailerResult result) {
 
 		if(result == null) {
 			result = new MailerResult();
 		}
-		MimeMessage mail = createMimeMessage(fromId, from, toId, to, cc, ccLists, bccLists, subject, body, attachments, result);
+		MimeMessage mail = createMimeMessage(fromId, from, toId, to, cc, bccLists, content, result);
 		if(mail != null) {
 			sendMessage(mail, result);
 		}
@@ -618,8 +891,7 @@ public class MailManager extends BasicManager {
 	}
 	
 	protected DBMail saveDBMessage(MailContext context, Identity fromId, String from, Identity toId, String to, 
-			Identity cc, List<ContactList> ccLists, List<ContactList> bccLists,
-			String metaId, String subject, String body, List<File> attachments, MailerResult result) {
+			Identity cc,  List<ContactList> bccLists, String metaId, MailContent content, MailerResult result) {
 		
 		try {
 			DBMailImpl mail = new DBMailImpl();
@@ -627,7 +899,7 @@ public class MailManager extends BasicManager {
 				result = new MailerResult();
 			}
 			
-			boolean makeRealMail = makeRealMail(toId, cc, ccLists, bccLists);
+			boolean makeRealMail = makeRealMail(toId, cc, bccLists);
 			Address fromAddress = null;
 			List<Address> toAddress = new ArrayList<Address>();
 			List<Address> ccAddress = new ArrayList<Address>();
@@ -664,11 +936,13 @@ public class MailManager extends BasicManager {
 			}
 			
 			mail.setMetaId(metaId);
+			String subject = content.getSubject();
 			if(subject != null && subject.length() > 500) {
 				logWarn("Cut a too long subkect in name. Size: " + subject.length(), null);
 				subject = subject.substring(0, 500);
 			}
 			mail.setSubject(subject);
+			String body = content.getBody();
 			if(body != null && body.length() > 16777210) {
 				logWarn("Cut a too long body in mail. Size: " + body.length(), null);
 				body = body.substring(0, 16000000);
@@ -750,16 +1024,14 @@ public class MailManager extends BasicManager {
 				mail.getRecipients().add(recipient);
 				createAddress(ccAddress, recipient, false, result, true);
 			}
-			
-			//add cc recipients
-			appendRecipients(mail, ccLists, toAddress, ccAddress, true, makeRealMail, result);
-			
+
 			//add bcc recipients
 			appendRecipients(mail, bccLists, toAddress, bccAddress, false, makeRealMail, result);
 			
 			dbInstance.getCurrentEntityManager().persist(mail);
 			
 			//save attachments
+			List<File> attachments = content.getAttachments();
 			if(attachments != null && !attachments.isEmpty()) {
 				for(File attachment:attachments) {
 
@@ -865,11 +1137,11 @@ public class MailManager extends BasicManager {
 		}
 	}
 	
-	private boolean makeRealMail(Identity toId, Identity cc, List<ContactList> ccLists, List<ContactList> bccLists) {
+	private boolean makeRealMail(Identity toId, Identity cc, List<ContactList> bccLists) {
 		//need real mail to???
 		boolean makeRealMail = false;
 		// can occur on self-registration
-		if (toId == null && cc == null && ccLists == null && bccLists == null) return true;
+		if (toId == null && cc == null && bccLists == null) return true;
 		
 		if(toId != null) {
 			makeRealMail |= wantRealMailToo(toId);
@@ -892,25 +1164,11 @@ public class MailManager extends BasicManager {
 			}
 		}
 		
-		//add bcc recipients
-		if(ccLists != null && !ccLists.isEmpty()) {
-			for(ContactList contactList:ccLists) {
-				for(Identity identityEmail:contactList.getIdentiEmails().values()) {
-					makeRealMail |= wantRealMailToo(identityEmail);
-				}
-				
-				if(!contactList.getStringEmails().isEmpty()) {
-					makeRealMail |= true;
-				}
-			}
-		}
-		
 		return makeRealMail;
 	}
 	
 	private MimeMessage createMimeMessage(Identity fromId, String mailFrom, Identity toId, String to, Identity ccId,
-			List<ContactList> ccLists, List<ContactList> bccLists,
-			String subject, String body, List<File> attachments, MailerResult result) {
+			List<ContactList> bccLists, MailContent content, MailerResult result) {
 		try {
 			Address from;
 			if(StringHelper.containsNonWhitespace(mailFrom)) {
@@ -945,23 +1203,6 @@ public class MailManager extends BasicManager {
 					ccList.add(ccAddress);
 				}
 			}
-
-			//add cc contact list
-			if(ccLists != null) {
-				for (ContactList contactList : ccLists) {
-					if(StringHelper.containsNonWhitespace(contactList.getName())) {
-						Address[] groupNames = InternetAddress.parse(contactList.getRFC2822Name() + ";");
-						for(Address groupName:groupNames) {
-							toList.add(groupName);
-						}
-					}
-					
-					Address[] members = contactList.getEmailsAsAddresses();
-					for(Address member:members) {
-						ccList.add(member);
-					}
-				}
-			}
 			
 			//add bcc contact lists
 			List<Address> bccList = new ArrayList<Address>();
@@ -984,7 +1225,7 @@ public class MailManager extends BasicManager {
 			Address[] tos = toList.toArray(new Address[toList.size()]);
 			Address[] ccs = ccList.toArray(new Address[ccList.size()]);
 			Address[] bccs = bccList.toArray(new Address[bccList.size()]);
-			return createMimeMessage(from, tos, ccs, bccs, subject, body, attachments, result);
+			return createMimeMessage(from, tos, ccs, bccs, content.getSubject(), content.getBody(), content.getAttachments(), result);
 		} catch (MessagingException e) {
 			logError("", e);
 			return null;
@@ -1203,7 +1444,7 @@ public class MailManager extends BasicManager {
 	 * @param bounceAdress must be a raw email, without anything else (no "bla bli <bla@bli.ch>" !)
 	 * @return
 	 */
-	public MimeMessage createMessage(Address bounceAdress) {
+	private MimeMessage createMessage(Address bounceAdress) {
 		String mailhost = WebappHelper.getMailConfig("mailhost");
 		String mailhostTimeout = WebappHelper.getMailConfig("mailTimeout");
 		boolean sslEnabled = Boolean.parseBoolean(WebappHelper.getMailConfig("sslEnabled"));
@@ -1249,7 +1490,8 @@ public class MailManager extends BasicManager {
 		String fromPlainAddress = fromAddress.getAddress();
 		return new InternetAddress(fromPlainAddress);
 	}
-	
+
+	@Override
 	public MimeMessage createMimeMessage(Address from, Address[] tos, Address[] ccs, Address[] bccs, String subject, String body,
 			List<File> attachments, MailerResult result) {
 		
@@ -1278,11 +1520,19 @@ public class MailManager extends BasicManager {
 
 			if (attachments != null && !attachments.isEmpty()) {
 				// with attachment use multipart message
-				Multipart multipart = new MimeMultipart();
+				Multipart multipart = new MimeMultipart("mixed");
 				// 1) add body part
-				BodyPart messageBodyPart = new MimeBodyPart();
-				messageBodyPart.setText(body);
-				multipart.addBodyPart(messageBodyPart);
+				if(containsHtml(body)) {
+					Multipart alternativePart = createMultipartAlternative(body);
+					MimeBodyPart wrap = new MimeBodyPart();
+					wrap.setContent(alternativePart);
+					multipart.addBodyPart(wrap);
+				} else {
+					BodyPart messageBodyPart = new MimeBodyPart();
+					messageBodyPart.setText(body);
+					multipart.addBodyPart(messageBodyPart);
+				}
+				
 				// 2) add attachments
 				for (File attachmentFile : attachments) {
 					// abort if attachment does not exist
@@ -1292,17 +1542,21 @@ public class MailManager extends BasicManager {
 								+ (attachmentFile == null ? null : attachmentFile.getAbsolutePath()), null);
 						return msg;
 					}
-					messageBodyPart = new MimeBodyPart();
+					BodyPart filePart = new MimeBodyPart();
 					DataSource source = new FileDataSource(attachmentFile);
-					messageBodyPart.setDataHandler(new DataHandler(source));
-					messageBodyPart.setFileName(attachmentFile.getName());
-					multipart.addBodyPart(messageBodyPart);
+					filePart.setDataHandler(new DataHandler(source));
+					filePart.setFileName(attachmentFile.getName());
+					multipart.addBodyPart(filePart);
 				}
 				// Put parts in message
 				msg.setContent(multipart);
 			} else {
 				// without attachment everything is easy, just set as text
-				msg.setText(body, "utf-8");
+				if(containsHtml(body)) {
+					msg.setContent(createMultipartAlternative(body));
+				} else {
+					msg.setText(body, "utf-8");
+				}
 			}
 			msg.setSentDate(new Date());
 			msg.saveChanges();
@@ -1322,6 +1576,32 @@ public class MailManager extends BasicManager {
 		}
 	}
 	
+	private Multipart createMultipartAlternative(String text)
+	throws MessagingException {
+		String pureText = new NekoHTMLFilter().filter(text, true);
+		MimeBodyPart textPart = new MimeBodyPart();
+		textPart.setText(pureText, "utf-8");
+		
+		MimeBodyPart htmlPart = new MimeBodyPart();
+		htmlPart.setText(text, "utf-8", "html");
+
+		Multipart multipart = new MimeMultipart("alternative");
+		multipart.addBodyPart(textPart);
+		multipart.addBodyPart(htmlPart);
+		return multipart;
+	}
+	
+	private boolean containsHtml(String text) {
+		if(text.contains("<html") || text.contains("<body") || text.contains("<p") || text.contains("<span")) {
+			return true;
+		}
+		if(text.contains("<HTML") || text.contains("<BODY") || text.contains("<P") || text.contains("<SPAN")) {
+			return true;
+		}
+		return false;
+	}
+
+	@Override
 	public void sendMessage(MimeMessage msg, MailerResult result){
 		try{
 			if(Settings.isJUnitTest()) {
diff --git a/src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java b/src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java
index a546d05f16521f55f12c4e61949fdbca0155dc8c..72560a23d1b3aa0803bcf33b265e65b1f64120d8 100644
--- a/src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java
+++ b/src/main/java/org/olat/core/util/mail/manager/MailNotificationsHandler.java
@@ -24,11 +24,13 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.logging.LogDelegator;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailModule;
 import org.olat.core.util.mail.model.DBMailLight;
 import org.olat.core.util.notifications.NotificationsHandler;
@@ -90,7 +92,7 @@ public class MailNotificationsHandler extends LogDelegator implements Notificati
 		// can't be loaded when already deleted
 		if (NotificationsManager.getInstance().isPublisherValid(p) && compareDate.before(latestNews)) {
 			try {
-				List<DBMailLight> inbox = MailManager.getInstance().getInbox(subscriber.getIdentity(), Boolean.TRUE, Boolean.FALSE, compareDate, 0, -1);
+				List<DBMailLight> inbox = CoreSpringFactory.getImpl(MailManager.class).getInbox(subscriber.getIdentity(), Boolean.TRUE, Boolean.FALSE, compareDate, 0, -1);
 				if(!inbox.isEmpty()) {
 					Translator translator = Util.createPackageTranslator(MailModule.class, locale);
 					si = new SubscriptionInfo(subscriber.getKey(), p.getType(), new TitleItem(translator.translate("mail.notification.type"), "o_co_icon"), null);
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailAdminController.java b/src/main/java/org/olat/core/util/mail/ui/MailAdminController.java
index 07dc92e25173b28cbe9aa0222e7b49aaf3e787e7..d1628abaece5c9f51d6a89693b8b1ae2a625d50e 100644
--- a/src/main/java/org/olat/core/util/mail/ui/MailAdminController.java
+++ b/src/main/java/org/olat/core/util/mail/ui/MailAdminController.java
@@ -19,125 +19,89 @@
  */
 package org.olat.core.util.mail.ui;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.form.flexible.FormItem;
-import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
-import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
-import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
-import org.olat.core.gui.components.form.flexible.impl.FormEvent;
-import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.segmentedview.SegmentViewComponent;
+import org.olat.core.gui.components.segmentedview.SegmentViewEvent;
+import org.olat.core.gui.components.segmentedview.SegmentViewFactory;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.util.Util;
 import org.olat.core.util.mail.MailModule;
-import org.olat.core.util.mail.MailUIFactory;
 
 /**
  * 
- * Description:<br>
- * Small administration to set on/off the intern mail system
- * 
- * <P>
- * Initial Date:  14 avr. 2011 <br>
+ * Initial date: 12.09.2013<br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
  */
-public class MailAdminController extends FormBasicController  {
+public class MailAdminController extends BasicController {
 
-	private MultipleSelectionElement enabled;
-	private SingleSelection userDefaultSettingEl;
+	private final Link settingsLink, templateLink;
+	private final SegmentViewComponent segmentView;
 	
-	private String[] values = {""};
-	private String[] keys = {"on"};
+	private final VelocityContainer mainVC;
+	
+	private MailSettingsAdminController settingsCtrl;
+	private MailTemplateAdminController templateCtrl;
 	
-
-	private String[] userSettingValues ;
-	private String[] userSettingKeys = {"intern.only","send.copy"};
-
 	public MailAdminController(UserRequest ureq, WindowControl wControl) {
-		super(ureq, wControl, null, Util.createPackageTranslator(MailModule.class, ureq.getLocale()));
+		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(MailModule.class, ureq.getLocale()));
 		
-		initForm(ureq);
-	}
-
-	@Override
-	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		this.setFormTitle("mail.admin.title");
-		this.setFormDescription("mail.admin.description");
-		this.setFormContextHelp(MailUIFactory.class.getPackage().getName(), "mail-admin.html", "chelp.mail-admin.title");
+		mainVC = createVelocityContainer("segments");
 		
-		boolean internEnabled = isEnabled();
-		enabled = uifactory.addCheckboxesHorizontal("mail.admin.intern.enabled", formLayout, keys, values, null);
-		enabled.select(keys[0], internEnabled);
-		enabled.addActionListener(this, FormEvent.ONCHANGE);
+		segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
+		settingsLink = LinkFactory.createLink("mail.settings", mainVC, this);
+		segmentView.addSegment(settingsLink, true);
 		
-		boolean realMailSetting = isUserDefaultSetting();
-		userSettingValues = new String[] {
-			translate("mail.admin.intern.only"),
-			translate("mail.admin.intern.real.mail")
-		};
-		userDefaultSettingEl = uifactory.addRadiosVertical("mail-system", "mail.admin.default.settings", formLayout, userSettingKeys, userSettingValues);
-		if(realMailSetting) {
-			userDefaultSettingEl.select(userSettingKeys[1], true);
-		} else {
-			userDefaultSettingEl.select(userSettingKeys[0], true);
-		}
-		userDefaultSettingEl.setEnabled(internEnabled);
-
-		final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
-		buttonGroupLayout.setRootForm(mainForm);
-		formLayout.add(buttonGroupLayout);
+		templateLink = LinkFactory.createLink("mail.template", mainVC, this);
+		segmentView.addSegment(templateLink, false);
 		
-		uifactory.addFormSubmitButton("save", formLayout);
+		mainVC.put("segments", segmentView);
+		doOpenSettings(ureq);
+		putInitialPanel(mainVC);
 	}
-	
+
+
 	@Override
 	protected void doDispose() {
 		//
 	}
 
 	@Override
-	protected void formOK(UserRequest ureq) {
-		boolean on = !enabled.getSelectedKeys().isEmpty();
-		setEnabled(on);
-		
-		if(userDefaultSettingEl.isOneSelected()) {
-			boolean realMailSetting = userDefaultSettingEl.getSelected() == 1;
-			setUserDefaultSetting(realMailSetting);
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(source == segmentView) {
+			if(event instanceof SegmentViewEvent) {
+				SegmentViewEvent sve = (SegmentViewEvent)event;
+				String segmentCName = sve.getComponentName();
+				Component clickedLink = mainVC.getComponent(segmentCName);
+				if (clickedLink == settingsLink) {
+					doOpenSettings(ureq);
+				} else if (clickedLink == templateLink) {
+					doOpenTemplate(ureq);
+				}
+			}
 		}
-		userDefaultSettingEl.setEnabled(on);
-		
-		getWindowControl().setInfo("saved");
 	}
 
-	@Override
-	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
-		if(source == enabled) {
-			boolean on = !enabled.getSelectedKeys().isEmpty();
-			userDefaultSettingEl.setEnabled(on);
+	private void doOpenSettings(UserRequest ureq) {
+		if(settingsCtrl == null) {
+			settingsCtrl = new MailSettingsAdminController(ureq, getWindowControl());
+			listenTo(settingsCtrl);
 		}
-		super.formInnerEvent(ureq, source, event);
+		mainVC.put("segmentCmp", settingsCtrl.getInitialComponent());
 	}
 
-	private boolean isEnabled() {
-		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
-		return config.isInternSystem();
-	}
-	
-	private void setEnabled(boolean enabled) {
-		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
-		config.setInterSystem(enabled);
-	}
-	
-	
-	private boolean isUserDefaultSetting() {
-		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
-		return config.isReceiveRealMailUserDefaultSetting();
-	}
-	
-	private void setUserDefaultSetting(boolean enabled) {
-		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
-		config.setReceiveRealMailUserDefaultSetting(enabled);
+	private void doOpenTemplate(UserRequest ureq) {
+		if(templateCtrl == null) {
+			templateCtrl = new MailTemplateAdminController(ureq, getWindowControl());
+			listenTo(templateCtrl);
+		}
+		mainVC.put("segmentCmp", templateCtrl.getInitialComponent());
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java b/src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java
index 9e3bfd8fe6449f18b38a1a06a324e28427686406..a83fbf2bb2e11976579fe00e2373cfe5eeccbf9b 100644
--- a/src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java
+++ b/src/main/java/org/olat/core/util/mail/ui/MailAttachmentMapper.java
@@ -25,7 +25,7 @@ import javax.servlet.http.HttpServletRequest;
 import org.olat.core.dispatcher.mapper.Mapper;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.media.NotFoundMediaResource;
-import org.olat.core.util.mail.manager.MailManager;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSMediaResource;
 
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailController.java b/src/main/java/org/olat/core/util/mail/ui/MailController.java
index 38fc45ed5ca16bef7cfdfd1e4241d577bbc29ab9..1df230da38d7485be1e2f656244dc6a1112e79b2 100644
--- a/src/main/java/org/olat/core/util/mail/ui/MailController.java
+++ b/src/main/java/org/olat/core/util/mail/ui/MailController.java
@@ -25,6 +25,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -42,8 +43,8 @@ import org.olat.core.id.UserConstants;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.filter.impl.OWASPAntiSamyXSSFilter;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailModule;
-import org.olat.core.util.mail.manager.MailManager;
 import org.olat.core.util.mail.model.DBMail;
 import org.olat.core.util.mail.model.DBMailAttachment;
 import org.olat.core.util.mail.model.DBMailRecipient;
@@ -71,7 +72,7 @@ public class MailController extends FormBasicController {
 		setTranslator(Util.createPackageTranslator(MailModule.class, ureq.getLocale()));
 		this.mail = mail;
 		this.back = back;
-		mailManager = MailManager.getInstance();
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		attachments = mailManager.getAttachments(mail);
 		if(!attachments.isEmpty()) {
 			mapperBaseURI = registerMapper(ureq, new MailAttachmentMapper(mailManager));
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailListController.java b/src/main/java/org/olat/core/util/mail/ui/MailListController.java
index c06efac08488c60da86716811b1be5788e1abd72..c8b4068a1bd2b2226c1cdf0ecd33d75c9cd77032 100644
--- a/src/main/java/org/olat/core/util/mail/ui/MailListController.java
+++ b/src/main/java/org/olat/core/util/mail/ui/MailListController.java
@@ -30,6 +30,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.ShortName;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -59,9 +60,9 @@ import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailModule;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.manager.MailManager;
 import org.olat.core.util.mail.model.DBMail;
 import org.olat.core.util.mail.model.DBMailLight;
 import org.olat.core.util.mail.model.DBMailRecipient;
@@ -118,7 +119,7 @@ public class MailListController extends BasicController implements Activateable2
 		this.metaId = metaId;
 		this.contextResolver = resolver;
 		
-		mailManager = MailManager.getInstance();
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
 		tableConfig.setDownloadOffered(true);
@@ -231,9 +232,9 @@ public class MailListController extends BasicController implements Activateable2
 		List<DBMailLight> mails;
 		if(outbox) {
 			if(StringHelper.containsNonWhitespace(metaId)) {
-				mails = MailManager.getInstance().getEmailsByMetaId(metaId);
+				mails = mailManager.getEmailsByMetaId(metaId);
 			} else {
-				mails = MailManager.getInstance().getOutbox(getIdentity(), 0, -1);
+				mails = mailManager.getOutbox(getIdentity(), 0, -1);
 			}
 			
 			//strip meta emails
@@ -249,7 +250,7 @@ public class MailListController extends BasicController implements Activateable2
 				}
 			}
 		} else {
-			mails = MailManager.getInstance().getInbox(getIdentity(), null, Boolean.TRUE, null, 0, -1);
+			mails = mailManager.getInbox(getIdentity(), null, Boolean.TRUE, null, 0, -1);
 		}
 		
 		//extract contexts
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailSettingsAdminController.java b/src/main/java/org/olat/core/util/mail/ui/MailSettingsAdminController.java
new file mode 100644
index 0000000000000000000000000000000000000000..fdf2863ae6de57f3872041e82c019c873dc62cf0
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/ui/MailSettingsAdminController.java
@@ -0,0 +1,143 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util.mail.ui;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.Util;
+import org.olat.core.util.mail.MailModule;
+import org.olat.core.util.mail.MailUIFactory;
+
+/**
+ * 
+ * Description:<br>
+ * Small administration to set on/off the intern mail system
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class MailSettingsAdminController extends FormBasicController  {
+
+	private MultipleSelectionElement enabled;
+	private SingleSelection userDefaultSettingEl;
+	
+	private String[] values = {""};
+	private String[] keys = {"on"};
+	
+
+	private String[] userSettingValues ;
+	private String[] userSettingKeys = {"intern.only","send.copy"};
+
+	public MailSettingsAdminController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, null, Util.createPackageTranslator(MailModule.class, ureq.getLocale()));
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormTitle("mail.admin.title");
+		setFormDescription("mail.admin.description");
+		setFormContextHelp(MailUIFactory.class.getPackage().getName(), "mail-admin.html", "chelp.mail-admin.title");
+		
+		boolean internEnabled = isEnabled();
+		enabled = uifactory.addCheckboxesHorizontal("mail.admin.intern.enabled", formLayout, keys, values, null);
+		enabled.select(keys[0], internEnabled);
+		enabled.addActionListener(this, FormEvent.ONCHANGE);
+		
+		boolean realMailSetting = isUserDefaultSetting();
+		userSettingValues = new String[] {
+			translate("mail.admin.intern.only"),
+			translate("mail.admin.intern.real.mail")
+		};
+		userDefaultSettingEl = uifactory.addRadiosVertical("mail-system", "mail.admin.default.settings", formLayout, userSettingKeys, userSettingValues);
+		if(realMailSetting) {
+			userDefaultSettingEl.select(userSettingKeys[1], true);
+		} else {
+			userDefaultSettingEl.select(userSettingKeys[0], true);
+		}
+		userDefaultSettingEl.setEnabled(internEnabled);
+
+		final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
+		buttonGroupLayout.setRootForm(mainForm);
+		formLayout.add(buttonGroupLayout);
+		
+		uifactory.addFormSubmitButton("save", buttonGroupLayout);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		boolean on = !enabled.getSelectedKeys().isEmpty();
+		setEnabled(on);
+		
+		if(userDefaultSettingEl.isOneSelected()) {
+			boolean realMailSetting = userDefaultSettingEl.getSelected() == 1;
+			setUserDefaultSetting(realMailSetting);
+		}
+		userDefaultSettingEl.setEnabled(on);
+		
+		getWindowControl().setInfo("saved");
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source == enabled) {
+			boolean on = !enabled.getSelectedKeys().isEmpty();
+			userDefaultSettingEl.setEnabled(on);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	private boolean isEnabled() {
+		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
+		return config.isInternSystem();
+	}
+	
+	private void setEnabled(boolean enabled) {
+		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
+		config.setInterSystem(enabled);
+	}
+	
+	
+	private boolean isUserDefaultSetting() {
+		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
+		return config.isReceiveRealMailUserDefaultSetting();
+	}
+	
+	private void setUserDefaultSetting(boolean enabled) {
+		MailModule config = (MailModule) CoreSpringFactory.getBean("mailModule");
+		config.setReceiveRealMailUserDefaultSetting(enabled);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailTemplateAdminController.java b/src/main/java/org/olat/core/util/mail/ui/MailTemplateAdminController.java
new file mode 100644
index 0000000000000000000000000000000000000000..10480489bae9cdb9350520f2b1c46a599044b4e7
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/ui/MailTemplateAdminController.java
@@ -0,0 +1,98 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util.mail.ui;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.Util;
+import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailModule;
+import org.olat.core.util.mail.MailUIFactory;
+
+/**
+ * 
+ * Description:<br>
+ * Customize the mail template
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class MailTemplateAdminController extends FormBasicController  {
+
+	private TextElement templateEl;
+	
+	private final MailManager mailManager;
+	
+	public MailTemplateAdminController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, null, Util.createPackageTranslator(MailModule.class, ureq.getLocale()));
+		
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormTitle("mail.template.title");
+		setFormDescription("mail.template.description");
+		setFormContextHelp(MailUIFactory.class.getPackage().getName(), "mail-admin-template.html", "chelp.mail-admin-template.title");
+		
+		String def = mailManager.getMailTemplate();
+		templateEl = uifactory.addTextAreaElement("mail.template", "mail.template", 10000, 25, 50, true, def, formLayout);
+
+		final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
+		buttonGroupLayout.setRootForm(mainForm);
+		formLayout.add(buttonGroupLayout);
+		
+		uifactory.addFormSubmitButton("save", buttonGroupLayout);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+		
+		String value = templateEl.getValue();
+		templateEl.clearError();
+		if(value.length() <= 0) {
+			templateEl.setErrorKey("", null);
+			allOk = false;
+		}
+		return allOk & super.validateFormLogic(ureq);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		String value = templateEl.getValue();
+		mailManager.setMailTemplate(value);
+		getWindowControl().setInfo("saved");
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java b/src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java
index 2361e68bc73b2bdeb0bf5d6a14724c4c165e5d63..3f53ab68ce5d0bad5c5360be9dcf881411189206 100644
--- a/src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java
+++ b/src/main/java/org/olat/core/util/mail/ui/MailTreeNode.java
@@ -19,9 +19,10 @@
  */
 package org.olat.core.util.mail.ui;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.components.tree.GenericTreeNode;
 import org.olat.core.id.Identity;
-import org.olat.core.util.mail.manager.MailManager;
+import org.olat.core.util.mail.MailManager;
 
 /**
  * 
@@ -49,7 +50,7 @@ public class MailTreeNode extends GenericTreeNode {
 
 	@Override
 	public String getIconDecorator1CssClass() {
-		if(MailManager.getInstance().hasNewMail(identity)) {
+		if(CoreSpringFactory.getImpl(MailManager.class).hasNewMail(identity)) {
 			return "b_mail_new";
 		}
 		return null;
diff --git a/src/main/java/org/olat/core/util/mail/ui/SendDocumentsByEMailController.java b/src/main/java/org/olat/core/util/mail/ui/SendDocumentsByEMailController.java
index 758d43d46dfa44e6c27aae33ef496ecde79016ff..ebf9a41f92c0269e8ef98faf9e1de29d96c9f302 100644
--- a/src/main/java/org/olat/core/util/mail/ui/SendDocumentsByEMailController.java
+++ b/src/main/java/org/olat/core/util/mail/ui/SendDocumentsByEMailController.java
@@ -24,8 +24,8 @@ import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.UUID;
 
-import org.apache.velocity.VelocityContext;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.events.SingleIdentityChosenEvent;
@@ -63,11 +63,11 @@ import org.olat.core.id.context.ContextEntry;
 import org.olat.core.util.CodeHelper;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailModule;
-import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.vfs.LocalFileImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
@@ -102,6 +102,7 @@ public class SendDocumentsByEMailController extends FormBasicController implemen
 	private List<File> attachments;
 	private List<IdentityWrapper> toValues = new ArrayList<IdentityWrapper>();
 
+	private final MailManager mailManager;
 	private final BaseSecurity securityManager;
 	private final boolean allowAttachments;
 
@@ -110,6 +111,7 @@ public class SendDocumentsByEMailController extends FormBasicController implemen
 				Util.createPackageTranslator(MailModule.class, ureq.getLocale())));
 		setBasePackage(MailModule.class);
 
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		securityManager = BaseSecurityManager.getInstance();
 		allowAttachments = !FolderConfig.getSendDocumentLinkOnly();
 
@@ -516,19 +518,21 @@ public class SendDocumentsByEMailController extends FormBasicController implemen
 	protected void sendEmail(List<Identity> tos, String subject, String body, UserRequest ureq) {
 		File[] attachmentArray = null;
 		if (attachments != null && !attachments.isEmpty() && allowAttachments) {
-			attachmentArray = new File[attachments.size()];
-			attachmentArray = attachments.toArray(attachmentArray);
+			attachmentArray = attachments.toArray(new File[attachments.size()]);
 		}
 
-		MailTemplate mailTemplate = new MailTemplate(subject, body, attachmentArray) {
-			@Override
-			public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-				// nothing to do;
-			}
-		};
+		MailerResult result = new MailerResult();
+		String metaId = UUID.randomUUID().toString().replace("-", "");
+		for(Identity to:tos) {
+			MailBundle bundle = new MailBundle();
+			bundle.setToId(to);
+			bundle.setMetaId(metaId);
+			bundle.setFromId(ureq.getIdentity());
+			bundle.setContent(subject, body, attachmentArray);
+			result.append(mailManager.sendMessage(bundle));
+		}
 
-		MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, tos, null, mailTemplate, ureq.getIdentity());
-		MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale());
+		MailHelper.printErrorsAndWarnings(result, getWindowControl(), ureq.getLocale());
 	}
 
 	public class FileInfo {
diff --git a/src/main/java/org/olat/core/util/mail/ui/_content/segments.html b/src/main/java/org/olat/core/util/mail/ui/_content/segments.html
new file mode 100644
index 0000000000000000000000000000000000000000..3d776f938257908fbbff3a476ab4ca371c009513
--- /dev/null
+++ b/src/main/java/org/olat/core/util/mail/ui/_content/segments.html
@@ -0,0 +1,7 @@
+<div class="b_clearfix">
+	$r.render("segments") <br/>	
+		
+	#if($r.available("segmentCmp"))
+		$r.render("segmentCmp")
+	#end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/en/ENRunController.java b/src/main/java/org/olat/course/nodes/en/ENRunController.java
index 99b688d27b15919295d0cc274f7609d871f1e829..8bbee772a671b05ed2f076e898bfa2bb5db5a60d 100644
--- a/src/main/java/org/olat/course/nodes/en/ENRunController.java
+++ b/src/main/java/org/olat/course/nodes/en/ENRunController.java
@@ -140,11 +140,11 @@ public class ENRunController extends BasicController implements GenericEventList
 
 		Identity identity = userCourseEnv.getIdentityEnvironment().getIdentity();
 		enrolledGroup = enrollmentManager.getBusinessGroupWhereEnrolled(identity, enrollableGroupKeys, enrollableAreaKeys, courseGroupManager.getCourseResource());
-		waitingListGroup = enrollmentManager.getBusinessGroupWhereInWaitingList(identity, enrollableGroupKeys, enrollableAreaKeys, courseGroupManager);
+		waitingListGroup = enrollmentManager.getBusinessGroupWhereInWaitingList(identity, enrollableGroupKeys, enrollableAreaKeys);
 		registerGroupChangedEvents(enrollableGroupKeys, enrollableAreaKeys, ureq.getIdentity());
 		// Set correct view
 		enrollVC = createVelocityContainer("enrollmultiple");
-		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys, courseGroupManager);
+		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys);
 		
 		tableCtr = createTableController(ureq, enrollmentManager.hasAnyWaitingList(groups));
 		
@@ -255,7 +255,7 @@ public class ENRunController extends BasicController implements GenericEventList
 
 	private void doEnrollMultipleView(UserRequest ureq) {
 		// 1. Fetch groups from database
-		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys, courseGroupManager);
+		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys);
 		List<Integer> members = courseGroupManager.getNumberOfMembersFromGroups(groups);
 		// 2. Build group list
 		groupListModel = new BusinessGroupTableModelWithMaxSize(groups, members, getTranslator(), ureq.getIdentity(), cancelEnrollEnabled);
@@ -299,14 +299,14 @@ public class ENRunController extends BasicController implements GenericEventList
 	 * Add as listener to BusinessGroups so we are being notified about changes.
 	 */
 	private void registerGroupChangedEvents(List<Long> enrollableGroupKeys, List<Long> enrollableAreaKeys, Identity identity) {
-		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys, courseGroupManager);
+		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys);
 		for (BusinessGroup group: groups) {
 			CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, identity, group);
 		}
 	}
 	
 	private void deregisterGroupChangedEvents(List<Long> enrollableGroupKeys, List<Long> enrollableAreaKeys) {
-		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys, courseGroupManager);
+		List<BusinessGroup> groups = enrollmentManager.loadGroupsFromNames(enrollableGroupKeys, enrollableAreaKeys);
 		for (BusinessGroup group:groups) {
 			CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, group);
 		}
diff --git a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
index fad6ce3783e2e61ac8494c60139ae1390904d145..ea81bf2af3ab1397263e1edf995441d8075e2201 100644
--- a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
+++ b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
@@ -35,12 +35,13 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
 import org.olat.core.manager.BasicManager;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.nodes.ENCourseNode;
 import org.olat.course.properties.CoursePropertyManager;
@@ -70,6 +71,8 @@ import org.springframework.stereotype.Service;
 @Service("enrollmentManager")
 public class EnrollmentManager extends BasicManager {
 
+	@Autowired
+	private MailManager mailManager;
 	@Autowired
 	private BGAreaManager areaManager;
 	@Autowired
@@ -87,7 +90,7 @@ public class EnrollmentManager extends BasicManager {
 		if (isLogDebugEnabled()) logDebug("doEnroll");
 		// check if the user is already enrolled (user can be enrooled only in one group)
 		if ( ( getBusinessGroupWhereEnrolled( identity, groupKeys, areaKeys, cgm.getCourseResource()) == null)
-			  && ( getBusinessGroupWhereInWaitingList( identity, groupKeys, areaKeys, cgm) == null) ) {
+			  && ( getBusinessGroupWhereInWaitingList(identity, groupKeys, areaKeys) == null) ) {
 			if (isLogDebugEnabled()) logDebug("Identity is not enrolled identity=" + identity.getName() + "  group=" + group.getName());
 			// 1. Check if group has max size defined. If so check if group is full
 			// o_clusterREVIEW cg please review it - also where does the group.getMaxParticipants().equals("") come from??
@@ -131,11 +134,14 @@ public class EnrollmentManager extends BasicManager {
 
 		// 3. Send notification mail
 		MailTemplate mailTemplate = BGMailHelper.createRemoveMyselfMailTemplate(enrolledGroup, identity);
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 		//fxdiff VCRP-16: intern mail system
 		MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString());
-		MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, Collections.singletonList(identity), null, mailTemplate, null);
-		MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale());
+		MailerResult result = new MailerResult();
+		MailBundle bundle = mailManager.makeMailBundle(context, identity, mailTemplate, null, null, result);
+		if(bundle != null) {
+			mailManager.sendMessage(bundle);
+		}
+		MailHelper.printErrorsAndWarnings(result, wControl, trans.getLocale());
 	}
 
 	public void doCancelEnrollmentInWaitingList(final Identity identity, final BusinessGroup enrolledWaitingListGroup, final ENCourseNode enNode,
@@ -152,11 +158,14 @@ public class EnrollmentManager extends BasicManager {
 
 		// 3. Send notification mail
 		MailTemplate mailTemplate = BGMailHelper.createRemoveWaitinglistMailTemplate(enrolledWaitingListGroup, identity);
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 		//fxdiff VCRP-16: intern mail system
 		MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString());
-		MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, Collections.singletonList(identity), null, mailTemplate, null);
-		MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale());
+		MailerResult result = new MailerResult();
+		MailBundle bundle = mailManager.makeMailBundle(context, identity, mailTemplate, null, null, result);
+		if(bundle != null) {
+			mailManager.sendMessage(bundle);
+		}
+		MailHelper.printErrorsAndWarnings(result, wControl, trans.getLocale());
 	}
 
 	// Helper Methods
@@ -207,8 +216,8 @@ public class EnrollmentManager extends BasicManager {
 	 * @return true if this identity is any waiting-list group in this course that
 	 *         has a name that is in the group names list
 	 */
-	protected BusinessGroup getBusinessGroupWhereInWaitingList(Identity identity, List<Long> groupKeys, List<Long> areaKeys, CourseGroupManager cgm) {
-		List<BusinessGroup> groups = loadGroupsFromNames(groupKeys, areaKeys, cgm);
+	protected BusinessGroup getBusinessGroupWhereInWaitingList(Identity identity, List<Long> groupKeys, List<Long> areaKeys) {
+		List<BusinessGroup> groups = loadGroupsFromNames(groupKeys, areaKeys);
 		// loop over all business-groups
 		for (BusinessGroup businessGroup:groups) {
 			if (securityManager.isIdentityInSecurityGroup(identity, businessGroup.getWaitingGroup())) { 
@@ -225,7 +234,7 @@ public class EnrollmentManager extends BasicManager {
 	 *         not found it won't be in the list. So groupNames.size() can very
 	 *         well by different than loadGroupsFromNames().size()
 	 */
-	protected List<BusinessGroup> loadGroupsFromNames(List<Long> groupKeys, List<Long> areaKeys, CourseGroupManager cgm) {
+	protected List<BusinessGroup> loadGroupsFromNames(List<Long> groupKeys, List<Long> areaKeys) {
 		List<BusinessGroup> groups = new ArrayList<BusinessGroup>(businessGroupService.loadBusinessGroups(groupKeys));
 		List<BusinessGroup> areaGroups = areaManager.findBusinessGroupsOfAreaKeys(areaKeys);
 		// add groups from areas
@@ -281,13 +290,13 @@ public class EnrollmentManager extends BasicManager {
 		}
 		// 4. Send notification mail
 		MailTemplate mailTemplate = BGMailHelper.createAddMyselfMailTemplate(group, identity);
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
-		//fxdiff VCRP-16: intern mail system
 		MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString());
-		MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, Collections.singletonList(identity), null, mailTemplate, null);
-		MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale());
-
-
+		MailerResult result = new MailerResult();
+		MailBundle bundle = mailManager.makeMailBundle(context, identity, mailTemplate, null, null, result);
+		if(bundle != null) {
+			mailManager.sendMessage(bundle);
+		}
+		MailHelper.printErrorsAndWarnings(result, wControl, trans.getLocale());
 		return true;
 	}
 
@@ -317,12 +326,14 @@ public class EnrollmentManager extends BasicManager {
 		}		
 		// 4. Send notification mail
 		MailTemplate mailTemplate = BGMailHelper.createAddWaitinglistMailTemplate(group, identity);
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 		//fxdiff VCRP-16: intern mail system
 		MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString());
-		MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, Collections.singletonList(identity), null, mailTemplate, null);
-		MailHelper.printErrorsAndWarnings(mailerResult, wControl, trans.getLocale());
-
+		MailerResult result = new MailerResult();
+		MailBundle bundle = mailManager.makeMailBundle(context, identity, mailTemplate, null, null, result);
+		if(bundle != null) {
+			mailManager.sendMessage(bundle);
+		}
+		MailHelper.printErrorsAndWarnings(result, wControl, trans.getLocale());
 		return true;
 	}
 
diff --git a/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java b/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java
index c96022f65daf0416b8bdaee58e5f19fba2af40a7..4d364c5bbecea2e0abc98c7935499b31ea301ab3 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQEditReplaceWizard.java
@@ -25,8 +25,10 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import org.apache.velocity.VelocityContext;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -39,11 +41,13 @@ import org.olat.core.gui.control.generic.wizard.WizardController;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLATRuntimeException;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailNotificationEditController;
 import org.olat.core.util.mail.MailTemplate;
-import org.olat.core.util.mail.MailerWithTemplate;
+import org.olat.core.util.mail.MailerResult;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.CourseNode;
@@ -103,6 +107,8 @@ public class IQEditReplaceWizard extends WizardController {
 	private Link nextBtn, showFileButton;
 	private MailNotificationEditController mailCtr;
 	private ReferencableEntriesSearchController searchCtr;
+	
+	private MailManager mailManager;
 
 	/**
 	 * a number of identities with qti.ser entry
@@ -121,6 +127,7 @@ public class IQEditReplaceWizard extends WizardController {
 		super(ureq, wControl, STEPS);
 		
 		setBasePackage(IQEditReplaceWizard.class);
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		
 		this.course = course;
 		this.courseNode = courseNode;
@@ -150,14 +157,15 @@ public class IQEditReplaceWizard extends WizardController {
 		if(source == mailCtr && event == Event.DONE_EVENT) {
 			MailTemplate mailTemplate = mailCtr.getMailTemplate();
 			if(mailTemplate != null) {
-				List<Identity> recipientsCC = null;
+				MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
+				String metaId = UUID.randomUUID().toString().replace("-", "");
+				MailerResult result = new MailerResult();
+				MailBundle[] bundles = mailManager.makeMailBundles(context, learners, mailTemplate, getIdentity(), metaId, result);
+				result.append(mailManager.sendMessage(bundles));
 				if(mailTemplate.getCpfrom()) {
-					recipientsCC = new ArrayList<Identity>();
-					recipientsCC.add(ureq.getIdentity());
+					MailBundle ccBundle = mailManager.makeMailBundle(context, getIdentity(), mailTemplate, getIdentity(), metaId, result);
+					result.append(mailManager.sendMessage(ccBundle));
 				}
-				//fxdiff VCRP-16: intern mail system
-				MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-				MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, learners, recipientsCC, mailCtr.getMailTemplate(), ureq.getIdentity());
 			}
 			fireEvent(ureq, Event.DONE_EVENT);
 		} else if (source == searchCtr && event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) {
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java
index 60580fdeccbf41d55d8ea05328ec1229937a4c47..5b4ab059e2062c14eac84b888475c2ea16a36ff5 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectGroupController.java
@@ -25,8 +25,8 @@
 
 package org.olat.course.nodes.projectbroker;
 
-import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 import org.olat.admin.securitygroup.gui.GroupController;
 import org.olat.admin.securitygroup.gui.IdentitiesAddEvent;
@@ -43,12 +43,13 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.activity.ActionType;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.course.nodes.projectbroker.datamodel.Project;
 import org.olat.course.nodes.projectbroker.service.ProjectBrokerManagerFactory;
 import org.olat.course.nodes.projectbroker.service.ProjectBrokerModuleConfiguration;
@@ -70,6 +71,7 @@ public class ProjectGroupController extends BasicController {
 
 	private ProjectBrokerModuleConfiguration projectBrokerModuleConfiguration;
 	
+	private final MailManager mailManager;
 	private final BusinessGroupService businessGroupService;
 
 	/**
@@ -80,6 +82,7 @@ public class ProjectGroupController extends BasicController {
 	public ProjectGroupController(UserRequest ureq, WindowControl wControl, Project project, ProjectBrokerModuleConfiguration projectBrokerModuleConfiguration) {
 		super(ureq, wControl);
 		getUserActivityLogger().setStickyActionType(ActionType.admin);
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
 		this.project = project;
 		this.projectBrokerModuleConfiguration = projectBrokerModuleConfiguration;
@@ -157,20 +160,18 @@ public class ProjectGroupController extends BasicController {
 			identitiesMoveEvent.setMovedIdentities(response.getAddedIdentities());
 			identitiesMoveEvent.setNotMovedIdentities(response.getIdentitiesAlreadyInGroup());
 			// send mail for all of them
-			MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 			MailTemplate mailTemplate = identitiesMoveEvent.getMailTemplate();
 			if (mailTemplate != null) {
-				List<Identity> ccIdentities = new ArrayList<Identity>();
+				MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
+				String metaId = UUID.randomUUID().toString().replace("-", "");
+				MailerResult result = new MailerResult();
+				MailBundle[] bundles = mailManager.makeMailBundles(context, identitiesMoveEvent.getMovedIdentities(), mailTemplate, null, metaId, result);
+				result.append(mailManager.sendMessage(bundles));
 				if(mailTemplate.getCpfrom()) {
-					// add sender as CC 
-					ccIdentities.add(urequest.getIdentity()); 
-				} else {
-					ccIdentities = null;	
+					MailBundle ccBundle = mailManager.makeMailBundle(context, urequest.getIdentity(), mailTemplate, null, metaId, result);
+					result.append(mailManager.sendMessage(ccBundle));
 				}
-				//fxdiff VCRP-16: intern mail system
-				MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-				MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, identitiesMoveEvent.getMovedIdentities(), ccIdentities, mailTemplate, null);
-				MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), urequest.getLocale());
+				MailHelper.printErrorsAndWarnings(result, getWindowControl(), urequest.getLocale());
 			}
 			fireEvent(urequest, Event.CHANGED_EVENT );		
 			// Participant and waiting-list were changed => reload both
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java
index 73b223f1dc62f295a8e6888fe13040fa6dcff92e..58b4d7ad254cdd2a3c413d225decd874b2a4337a 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerMailerImpl.java
@@ -25,10 +25,10 @@
 
 package org.olat.course.nodes.projectbroker.service;
 
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
+import java.util.UUID;
 
 import org.apache.velocity.VelocityContext;
 import org.olat.basesecurity.BaseSecurityManager;
@@ -40,11 +40,12 @@ import org.olat.core.id.UserConstants;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Formatter;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.ProjectBrokerCourseNode;
 import org.olat.course.nodes.projectbroker.datamodel.Project;
@@ -178,16 +179,15 @@ public class ProjectBrokerMailerImpl implements ProjectBrokerMailer {
   // Private Methods	
   //////////////////
 	private MailerResult sendEmail(Identity enrolledIdentity, Project project, String subject, String body, Locale locale) {
-		MailTemplate enrolledMailTemplate = this.createMailTemplate(project, enrolledIdentity, subject, body, locale );
-		// TODO: cg/12.01.2010 in der Methode sendMailUsingTemplateContext wurden die Variablen nicht ersetzt (Fehler oder falsch angewendet?) 
-		//       als Workaround wurde die Methode sendMailAsSeparateMails verwendet
-		List<Identity> enrolledIdentityList = new ArrayList<Identity>();
-		enrolledIdentityList.add(enrolledIdentity);
-		//fxdiff VCRP-16: intern mail system
+		MailTemplate enrolledMailTemplate = createMailTemplate(project, enrolledIdentity, subject, body, locale );
 		MailContext context = new MailContextImpl(project.getProjectBroker(), null, null);
-		MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, enrolledIdentityList, null, enrolledMailTemplate, null);
-		log.audit("ProjectBroker: sendEmail to identity.name=" + enrolledIdentity.getName() + " , mailerResult.returnCode=" + mailerResult.getReturnCode());
-		return mailerResult;
+		MailerResult result = new MailerResult();
+		MailBundle bundle = CoreSpringFactory.getImpl(MailManager.class).makeMailBundle(context, enrolledIdentity, enrolledMailTemplate, null, null, result);
+		if(bundle != null) {
+			CoreSpringFactory.getImpl(MailManager.class).sendMessage(bundle);
+		}
+		log.audit("ProjectBroker: sendEmail to identity.name=" + enrolledIdentity.getName() + " , mailerResult.returnCode=" + result.getReturnCode());
+		return result;
 	}
 
 	private MailerResult sendEmailToGroup(SecurityGroup group, Identity enrolledIdentity, Project project, String subject, String body, Locale locale) {
@@ -199,11 +199,14 @@ public class ProjectBrokerMailerImpl implements ProjectBrokerMailer {
 			if (identityNames.length()>0) identityNames.append(",");
 			identityNames.append(identity.getName());
 		}
-		//fxdiff VCRP-16: intern mail system
 		MailContext context = new MailContextImpl(project.getProjectBroker(), null, null);
-		MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, projectManagerList, null, enrolledMailTemplate, null);
-		log.audit("ProjectBroker: sendEmailToGroup: identities=" + identityNames.toString() + " , mailerResult.returnCode=" + mailerResult.getReturnCode());
-		return mailerResult;
+		String metaId = UUID.randomUUID().toString().replace("-", "");
+		
+		MailerResult result = new MailerResult();
+		MailBundle[] bundles = CoreSpringFactory.getImpl(MailManager.class).makeMailBundles(context, projectManagerList, enrolledMailTemplate, null, metaId, result);
+		result.append(CoreSpringFactory.getImpl(MailManager.class).sendMessage(bundles));
+		log.audit("ProjectBroker: sendEmailToGroup: identities=" + identityNames.toString() + " , mailerResult.returnCode=" + result.getReturnCode());
+		return result;
 	}
 
 	private MailerResult sendEmailProjectChanged(SecurityGroup group, Identity changer, Project project, String subject, String body, Locale locale) {
@@ -215,11 +218,12 @@ public class ProjectBrokerMailerImpl implements ProjectBrokerMailer {
 			if (identityNames.length()>0) identityNames.append(",");
 			identityNames.append(identity.getName());
 		}
-		//fxdiff VCRP-16: intern mail system
 		MailContext context = new MailContextImpl(project.getProjectBroker(), null, null);
-		MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, projectManagerList, null, enrolledMailTemplate, null);
-		log.audit("ProjectBroker: sendEmailToGroup: identities=" + identityNames.toString() + " , mailerResult.returnCode=" + mailerResult.getReturnCode());
-		return mailerResult;
+		MailerResult result = new MailerResult();
+		MailBundle[] bundles = CoreSpringFactory.getImpl(MailManager.class).makeMailBundles(context, projectManagerList, enrolledMailTemplate, null, null, result);
+		result.append(CoreSpringFactory.getImpl(MailManager.class).sendMessage(bundles));
+		log.audit("ProjectBroker: sendEmailToGroup: identities=" + identityNames.toString() + " , mailerResult.returnCode=" + result.getReturnCode());
+		return result;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxController.java b/src/main/java/org/olat/course/nodes/ta/DropboxController.java
index 1e68317bd93f49515df36c9a8f236f3b0f89ce8f..640487b179d66674e238b35f0a2a37d30c59be27 100644
--- a/src/main/java/org/olat/course/nodes/ta/DropboxController.java
+++ b/src/main/java/org/olat/course/nodes/ta/DropboxController.java
@@ -31,7 +31,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -39,6 +38,7 @@ import org.apache.velocity.VelocityContext;
 import org.apache.velocity.context.Context;
 import org.olat.admin.quota.QuotaConstants;
 import org.olat.commons.file.filechooser.FileChooserController;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.meta.MetaInfo;
 import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged;
 import org.olat.core.commons.modules.bc.vfs.OlatNamedContainerImpl;
@@ -59,12 +59,12 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.UserConstants;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.Formatter;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
-import org.olat.core.util.mail.MailTemplate;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.notifications.ContextualSubscriptionController;
 import org.olat.core.util.notifications.NotificationsManager;
 import org.olat.core.util.notifications.SubscriptionContext;
@@ -273,17 +273,13 @@ public class DropboxController extends BasicController {
 					if (sendEmail == null) sendEmail = Boolean.FALSE;
 					boolean sendMailError = false;
 					if (sendEmail.booleanValue()) {
-						MailTemplate mailTempl = new MailTemplate(translate("conf.mail.subject"), confirmation, null) {
-
-							@Override
-							public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-								// nothing to do
-							}
-						};
-							
-						//fxdiff VCRP-16: intern mail system
+						//send mail
 						MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-						MailerResult result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, Collections.singletonList(ureq.getIdentity()), null, mailTempl, null);
+						MailBundle bundle = new MailBundle();
+						bundle.setContext(context);
+						bundle.setToId(ureq.getIdentity());
+						bundle.setContent(translate("conf.mail.subject"), confirmation);
+						MailerResult result = CoreSpringFactory.getImpl(MailManager.class).sendMessage(bundle);
 						if(result.getFailedIdentites().size() > 0) {
 							List<Identity> disabledIdentities = new ArrayList<Identity>();
 							disabledIdentities = result.getFailedIdentites();
diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
index 9cf2fbb5a967fb377df3dc0a572663628e028a9d..d506ee3ff7bb7b3a60ce28e33a262caff7de4614 100644
--- a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
+++ b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
@@ -26,11 +26,10 @@
 package org.olat.course.nodes.ta;
 
 import java.io.File;
-import java.util.Collections;
 import java.util.List;
 
-import org.apache.velocity.VelocityContext;
 import org.olat.admin.quota.QuotaConstants;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.FolderEvent;
 import org.olat.core.commons.modules.bc.FolderRunController;
@@ -59,11 +58,11 @@ import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
-import org.olat.core.util.mail.MailTemplate;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.notifications.SubscriptionContext;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.LocalFolderImpl;
@@ -285,19 +284,16 @@ public class DropboxScoringViewController extends BasicController {
 					String link = BusinessControlFactory.getInstance().getAsURIString(bc, true);
 					
 					log.debug("DEBUG : Returnbox notification email with link=" + link);
-					MailTemplate mailTempl = new MailTemplate(translate("returnbox.email.subject"), translate(
-							"returnbox.email.body", new String[] { userCourseEnv.getCourseEnvironment().getCourseTitle(), node.getShortTitle(),
-									folderEvent.getFilename(), link }), null) {
+					String subject = translate("returnbox.email.subject");
+					String body = translate("returnbox.email.body", new String[] { userCourseEnv.getCourseEnvironment().getCourseTitle(), node.getShortTitle(),
+									folderEvent.getFilename(), link });
 
-						@Override
-						public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-							// nothing to do
-						}
-					};
-					//fxdiff VCRP-16: intern mail system
 					MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-					MailerResult result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, Collections.singletonList(student), null, mailTempl, null);
-					
+					MailBundle bundle = new MailBundle();
+					bundle.setContext(context);
+					bundle.setToId(student);
+					bundle.setContent(subject, body);
+					MailerResult result = CoreSpringFactory.getImpl(MailManager.class).sendMessage(bundle);
 					if(result.getReturnCode() > 0) {
 						am.appendToUserNodeLog(node, coach, student, "MAIL SEND FAILED TO:" + toMail + "; MailReturnCode: " + result.getReturnCode());
 						log.warn("Could not send email 'returnbox notification' to " + student + "with email=" + toMail);
diff --git a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java
index 1f90b5370658c874e54741fd1eadbfe2c663c809..4902754fe19049946d683077d441e2c239172c0a 100644
--- a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java
+++ b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java
@@ -27,10 +27,12 @@ package org.olat.course.nodes.ta;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.context.Context;
 import org.olat.admin.quota.QuotaConstants;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderEvent;
 import org.olat.core.commons.modules.bc.FolderRunController;
 import org.olat.core.commons.modules.bc.vfs.OlatNamedContainerImpl;
@@ -55,17 +57,17 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
 import org.olat.core.id.UserConstants;
-import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Util;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailNotificationEditController;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.notifications.SubscriptionContext;
 import org.olat.core.util.vfs.Quota;
 import org.olat.core.util.vfs.QuotaManager;
@@ -143,6 +145,8 @@ public class TACourseNodeEditController extends ActivateableTabbableDefaultContr
 	private MailNotificationEditController mailCtr;
 	private CloseableModalController cmc;
 	private List<Identity> identitiesToBeNotified;
+	
+	private MailManager mailManager;
 
 	/**
 	 * @param ureq
@@ -154,6 +158,8 @@ public class TACourseNodeEditController extends ActivateableTabbableDefaultContr
 	public TACourseNodeEditController(UserRequest ureq, WindowControl wControl, ICourse course, TACourseNode node,
 			CourseGroupManager groupMgr, UserCourseEnvironment euce) {
 		super(ureq, wControl);
+		
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 
 		this.node = node;
 		//o_clusterOk by guido: save to hold reference to course inside editor
@@ -524,18 +530,17 @@ public class TACourseNodeEditController extends ActivateableTabbableDefaultContr
 	private void sendNotificationEmail(UserRequest ureq, MailTemplate mailTemplate, List<Identity> recipients) {
 	// send the notification mail
 		if (mailTemplate != null) {
-			MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 			Identity sender = ureq.getIdentity();
-			List<Identity> ccIdentities = new ArrayList<Identity>();
+			MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
+			MailerResult result = new MailerResult();
+			String metaId = UUID.randomUUID().toString().replace("-", "");
+			MailBundle[] bundles = mailManager.makeMailBundles(context, recipients, mailTemplate, sender, metaId, result);
+			result.append(mailManager.sendMessage(bundles));
 			if(mailTemplate.getCpfrom()) {
-				ccIdentities.add(sender);
-			} else {
-				ccIdentities = null;	
+				MailBundle ccBundle = mailManager.makeMailBundle(context, sender, mailTemplate, sender, metaId, result);
+				result.append(mailManager.sendMessage(ccBundle));
 			}
-			//fxdiff VCRP-16: intern mail system
-			MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-			MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, recipients, ccIdentities, mailTemplate, sender);
-			MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale());
+			MailHelper.printErrorsAndWarnings(result, getWindowControl(), ureq.getLocale());
 		}
 	}
 	
diff --git a/src/main/java/org/olat/course/statistic/ExportManager.java b/src/main/java/org/olat/course/statistic/ExportManager.java
index 8ec2f7615889fdc9bad4911680da752247194769..27b5c1efcad130ccde087d47c0b4d373e43ebb8d 100644
--- a/src/main/java/org/olat/course/statistic/ExportManager.java
+++ b/src/main/java/org/olat/course/statistic/ExportManager.java
@@ -32,20 +32,18 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
-import javax.mail.MessagingException;
-import javax.mail.SendFailedException;
-import javax.mail.internet.AddressException;
-
-import org.olat.core.gui.translator.PackageTranslator;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.manager.BasicManager;
 import org.olat.core.util.ExportUtil;
+import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.ZipUtil;
 import org.olat.core.util.i18n.I18nManager;
-import org.olat.core.util.mail.Emailer;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.vfs.LocalFileImpl;
 import org.olat.core.util.vfs.LocalFolderImpl;
 import org.olat.core.util.vfs.VFSContainer;
@@ -207,18 +205,16 @@ public class ExportManager extends BasicManager {
 		if (locale == null) {
 			locale = I18nManager.getInstance().getCurrentThreadLocale();
 		}
-		Translator translator = new PackageTranslator(this.getClass().getPackage().getName(), locale);
-		
-		Emailer emailer = new Emailer(locale);
-		String subject = translator.translate(emailI18nSubkey+".subject");
-		String body = translator.translate(emailI18nSubkey+".body");
+		Translator translator = Util.createPackageTranslator(ExportManager.class, locale);
 		try {
-			emailer.sendEmail(email, subject, body);
-		} catch (AddressException e) {
-			log_.error("Error sending information email to user that file was saved successfully.", e);
-		} catch (SendFailedException e) {
-			log_.error("Error sending information email to user that file was saved successfully.", e);
-		} catch (MessagingException e) {
+			MailBundle bundle = new MailBundle();
+			bundle.setFrom(WebappHelper.getMailConfig("mailReplyTo"));
+			bundle.setTo(email);
+			bundle.setContent(translator.translate(emailI18nSubkey + ".subject"),
+					translator.translate(emailI18nSubkey+".body"));
+
+			CoreSpringFactory.getImpl(MailManager.class).sendMessage(bundle);
+		} catch (Exception e) {
 			log_.error("Error sending information email to user that file was saved successfully.", e);
 		}
 	}
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupMailing.java b/src/main/java/org/olat/group/manager/BusinessGroupMailing.java
index 1ab7a07827be232c4ce2465ebbf61419533887d1..be4bc901d7f5264d82f775111094d8fe479dfaa0 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupMailing.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupMailing.java
@@ -19,19 +19,19 @@
  */
 package org.olat.group.manager;
 
-import java.util.Collections;
 import java.util.List;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailPackage;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.group.BusinessGroupModule;
 import org.olat.group.BusinessGroupShort;
 import org.olat.group.model.BusinessGroupMembershipChange;
@@ -102,7 +102,7 @@ public class BusinessGroupMailing {
 	}
 		
 	protected static void sendEmail(Identity ureqIdentity, Identity identity, BusinessGroupShort group,
-			MailType type, MailPackage mailing, MailerWithTemplate mailer) {
+			MailType type, MailPackage mailing) {
 		
 		if(mailing != null && !mailing.isSendEmail()) {
 			return;
@@ -127,8 +127,13 @@ public class BusinessGroupMailing {
 			context = new MailContextImpl(null, null, "[BusinessGroup:" + group.getKey() + "]");
 		}
 		
+		MailerResult result = new MailerResult();
 		String metaId = mailing != null ? mailing.getUuid() : null;
-		MailerResult result = mailer.sendMailAsSeparateMails(context, Collections.singletonList(identity), null, template, ureqIdentity, metaId);
+		MailManager mailService = CoreSpringFactory.getImpl(MailManager.class);
+		MailBundle bundle = mailService.makeMailBundle(context, identity, template, ureqIdentity, metaId, result);
+		if(bundle != null) {
+			mailService.sendMessage(bundle);
+		}
 		if(mailing != null) {
 			mailing.appendResult(result);
 		}
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
index 30a5731295c394112efb5c742158e19c91549b96..b5572407a040cb8743d587144644ad9163b9b6f5 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
@@ -55,12 +55,13 @@ import org.olat.core.logging.activity.ActionType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.async.ProgressDelegate;
 import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailPackage;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.notifications.NotificationsManager;
 import org.olat.core.util.notifications.Subscriber;
 import org.olat.core.util.resource.OLATResourceableJustBeforeDeletedEvent;
@@ -148,7 +149,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	@Autowired
 	private NotificationsManager notificationsManager;
 	@Autowired
-	private MailerWithTemplate mailer;
+	private MailManager mailManager;
 	@Autowired
 	private ACService acService;
 	@Autowired
@@ -816,14 +817,14 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		deleteBusinessGroup(businessGroupTodelete);
 		dbInstance.commit();
 		// finally send email
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 		MailTemplate mailTemplate = BGMailHelper.createDeleteGroupMailTemplate(businessGroupTodelete, deletedBy);
 		if (mailTemplate != null) {
 			String metaId = UUID.randomUUID().toString();
 			MailContext context = new MailContextImpl(businessPath);
-			MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, users, null, mailTemplate, null, metaId);
-			//MailHelper.printErrorsAndWarnings(mailerResult, wControl, locale);
-			return mailerResult;
+			MailerResult result = new MailerResult();
+			MailBundle[] bundles = mailManager.makeMailBundles(context, users, mailTemplate, null, metaId, result);
+			result.append(mailManager.sendMessage(bundles));
+			return result;
 		}
 		return null;
 	}
@@ -880,14 +881,14 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 					ResourceReservation reservation =
 							reservationDao.createReservation(identityToAdd, "group_coach", expiration, group.getResource());
 					if(reservation != null) {
-						BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addCoach, mailing, mailer);
+						BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addCoach, mailing);
 						// logging
 						log.audit("Idenitity(.key):" + ureqIdentity.getKey() + " added identity '" + identityToAdd.getName() + "' to securitygroup with key " + group.getOwnerGroup().getKey());
 					}
 				}
 			} else {
 				internalAddCoach(ureqIdentity, identityToAdd, group, events);
-				BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addCoach, mailing, mailer);
+				BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addCoach, mailing);
 			}
 			return true;
 		}
@@ -930,12 +931,12 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 					ResourceReservation reservation =
 							reservationDao.createReservation(identityToAdd, "group_participant", expiration, group.getResource());
 					if(reservation != null) {
-						BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addParticipant, mailing, mailer);
+						BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addParticipant, mailing);
 					}
 				}
 			} else {
 				internalAddParticipant(ureqIdentity, identityToAdd, group, events);
-				BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addParticipant, mailing, mailer);
+				BusinessGroupMailing.sendEmail(ureqIdentity, identityToAdd, group, MailType.addParticipant, mailing);
 			}
 			return true;
 		}
@@ -1046,7 +1047,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 				transferFirstIdentityFromWaitingToParticipant(ureqIdentity, group, null, events);
 			}	
 			// send mail
-			BusinessGroupMailing.sendEmail(ureqIdentity, identity, group, MailType.removeParticipant, mailing, mailer);
+			BusinessGroupMailing.sendEmail(ureqIdentity, identity, group, MailType.removeParticipant, mailing);
 		}
 	}
 	
@@ -1183,7 +1184,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_TO_WAITING_LIST_ADDED, getClass(), LoggingResourceable.wrap(identity));
 		log.audit("Idenitity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getName() + "' to securitygroup with key " + group.getPartipiciantGroup().getKey());
 		// send mail
-		BusinessGroupMailing.sendEmail(ureqIdentity, identity, group, MailType.addToWaitingList, mailing, mailer);
+		BusinessGroupMailing.sendEmail(ureqIdentity, identity, group, MailType.addToWaitingList, mailing);
 	}
 	
 	@Override
@@ -1225,7 +1226,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_FROM_WAITING_LIST_REMOVED, getClass(), LoggingResourceable.wrap(identity));
 		log.audit("Idenitity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName() + "' from securitygroup with key " + group.getOwnerGroup().getKey());
 		// send mail
-		BusinessGroupMailing.sendEmail(ureqIdentity, identity, group, MailType.removeToWaitingList, mailing, mailer);
+		BusinessGroupMailing.sendEmail(ureqIdentity, identity, group, MailType.removeToWaitingList, mailing);
 	}
 	
 	@Override
@@ -1389,7 +1390,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 							ThreadLocalUserActivityLogger.setStickyActionType(formerStickyActionType);
 						}
 
-						BusinessGroupMailing.sendEmail(ureqIdentity, firstWaitingListIdentity, group, MailType.graduateFromWaitingListToParticpant, mailing, mailer);				
+						BusinessGroupMailing.sendEmail(ureqIdentity, firstWaitingListIdentity, group, MailType.graduateFromWaitingListToParticpant, mailing);				
 						counter++;
 				  }
 				}
diff --git a/src/main/java/org/olat/group/ui/wizard/BGEmailCompositionStepController.java b/src/main/java/org/olat/group/ui/wizard/BGEmailCompositionStepController.java
index 47b5055d2b6c52e451f65eee4f8e9c5f0dca3fb4..5b279ed495e22c48890a23250bd0d4499c45caef 100644
--- a/src/main/java/org/olat/group/ui/wizard/BGEmailCompositionStepController.java
+++ b/src/main/java/org/olat/group/ui/wizard/BGEmailCompositionStepController.java
@@ -23,9 +23,6 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
-
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.core.CoreSpringFactory;
@@ -41,9 +38,11 @@ import org.olat.core.gui.control.generic.wizard.StepsEvent;
 import org.olat.core.gui.control.generic.wizard.StepsRunContext;
 import org.olat.core.id.Identity;
 import org.olat.core.util.mail.ContactList;
-import org.olat.core.util.mail.Emailer;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
+import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailerResult;
 import org.olat.group.BusinessGroup;
 import org.olat.modules.co.ContactForm;
 
@@ -55,12 +54,14 @@ public class BGEmailCompositionStepController extends StepFormBasicController
 	
 	private ContactForm contactForm;
 	private final List<BusinessGroup> groups;
+	private final MailManager mailService;
 	private final BaseSecurity securityManager;
 	
 	public BGEmailCompositionStepController(UserRequest ureq, WindowControl wControl, Form rootForm,
 			StepsRunContext runContext, List<BusinessGroup> groups) {
 		super(ureq, wControl, rootForm, runContext, LAYOUT_CUSTOM, "wrapper");
 		
+		mailService = CoreSpringFactory.getImpl(MailManager.class);
 		securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
 		this.groups = groups;
 
@@ -118,16 +119,28 @@ public class BGEmailCompositionStepController extends StepFormBasicController
 	protected void formOK(UserRequest ureq) {
 		boolean success = false;
 		try {
-			Emailer emailer = new Emailer(getIdentity(), false);
-			List<File> attachments = contactForm.getAttachments();	
+			File[] attachments = contactForm.getAttachments();	
 			MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-			success = emailer.sendEmail(context, contactForm.getEmailToContactLists(), contactForm.getSubject(), contactForm.getBody(), attachments);
+			MailBundle bundle = new MailBundle();
+			bundle.setContext(context);
+			bundle.setFromId(getIdentity());
+			bundle.setContactLists(contactForm.getEmailToContactLists());
+			bundle.setContent(contactForm.getSubject(), contactForm.getBody(), attachments);
+			
+			MailerResult result = mailService.sendMessage(bundle);
+			success = result.isSuccessful();
 			if(contactForm.isTcpFrom()) {
-				success = emailer.sendEmailCC(context, contactForm.getEmailFrom(), contactForm.getSubject(), contactForm.getBody(), attachments);
+				
+				MailBundle ccBundle = new MailBundle();
+				ccBundle.setContext(context);
+				ccBundle.setFromId(getIdentity());
+				ccBundle.setCc(contactForm.getEmailFrom());
+				ccBundle.setContent(contactForm.getSubject(), contactForm.getBody(), attachments);
+				
+				MailerResult ccResult = mailService.sendMessage(ccBundle);
+				success = ccResult.isSuccessful();
 			}
-		} catch (AddressException e) {
-			logError(null, e);
-		} catch (MessagingException e) {
+		} catch (Exception e) {
 			logError(null, e);
 		}
 		
diff --git a/src/main/java/org/olat/login/auth/OLATAuthManager.java b/src/main/java/org/olat/login/auth/OLATAuthManager.java
index f34f98f5db25cf199390c4717cc400f5297fba1a..22d467b95fe0f76022785bc91579285a56d4a438 100644
--- a/src/main/java/org/olat/login/auth/OLATAuthManager.java
+++ b/src/main/java/org/olat/login/auth/OLATAuthManager.java
@@ -29,7 +29,6 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
-import org.apache.velocity.VelocityContext;
 import org.olat.basesecurity.Authentication;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
@@ -47,11 +46,11 @@ import org.olat.core.util.Encoder.Algorithm;
 import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
-import org.olat.core.util.mail.MailTemplate;
-import org.olat.core.util.mail.MailerWithTemplate;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.ldap.LDAPError;
@@ -83,6 +82,8 @@ public class OLATAuthManager extends BasicManager implements AuthenticationSPI {
 	private UserManager userManager;
 	@Autowired
 	private BaseSecurity securityManager;
+	@Autowired
+	private MailManager mailManager;
 	
 	/**
 	 * 
@@ -212,15 +213,13 @@ public class OLATAuthManager extends BasicManager implements AuthenticationSPI {
 		};
 		String subject = translator.translate("mail.pwd.subject", args);
 		String body = translator.translate("mail.pwd.body", args);
-		MailTemplate template = new MailTemplate(subject, body, null){
-			@Override
-			public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-				//
-			}
-		};
+
 		MailContext context = new MailContextImpl(null, null, "[Identity:" + identity.getKey() + "]");
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
-		mailer.sendMailAsSeparateMails(context, Collections.singletonList(identity), null, template, null, null);
+		MailBundle bundle = new MailBundle();
+		bundle.setContext(context);
+		bundle.setToId(identity);
+		bundle.setContent(subject, body);
+		mailManager.sendMessage(bundle);
 	}
 	
 	private boolean changeOlatPassword(Identity doer, Identity identity, String newPwd) {
diff --git a/src/main/java/org/olat/modules/co/ContactForm.java b/src/main/java/org/olat/modules/co/ContactForm.java
index 5a2636f52649d67b9082f22bc20b2ce6c216e811..7bf8aff43888660282b0d5006458553f9a5c00b3 100644
--- a/src/main/java/org/olat/modules/co/ContactForm.java
+++ b/src/main/java/org/olat/modules/co/ContactForm.java
@@ -279,12 +279,12 @@ public class ContactForm extends FormBasicController {
  			return tbody.getValue();
 	}
  	
- 	public List<File> getAttachments() {
+ 	public File[] getAttachments() {
  		List<File> attachments = new ArrayList<File>();
  		for(FormLink removeLink : attachmentLinks) {
  			attachments.add((File)removeLink.getUserObject());
  		}
- 		return attachments;
+ 		return attachments.toArray(new File[attachments.size()]);
  	}
  	
  	public void cleanUpAttachments() {
diff --git a/src/main/java/org/olat/modules/co/ContactFormController.java b/src/main/java/org/olat/modules/co/ContactFormController.java
index add55c8b1c034d08fb26b1acb6178076a231572d..822c71ab7fd6b7321f46c4a610e52c53f2d63248 100644
--- a/src/main/java/org/olat/modules/co/ContactFormController.java
+++ b/src/main/java/org/olat/modules/co/ContactFormController.java
@@ -33,8 +33,8 @@ import javax.mail.Address;
 import javax.mail.AuthenticationFailedException;
 import javax.mail.MessagingException;
 import javax.mail.SendFailedException;
-import javax.mail.internet.AddressException;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.panel.Panel;
@@ -54,11 +54,13 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.ContactMessage;
-import org.olat.core.util.mail.Emailer;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
 import org.olat.core.util.mail.MailLoggingAction;
+import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailerResult;
 
 /**
  * <b>Fires Event: </b>
@@ -100,7 +102,7 @@ import org.olat.core.util.mail.MailLoggingAction;
  */
 public class ContactFormController extends BasicController {
 	
-	OLog log = Tracing.createLoggerFor(this.getClass());
+	private static final OLog log = Tracing.createLoggerFor(ContactFormController.class);
 	//
 	private Identity emailFrom;
 	
@@ -109,6 +111,8 @@ public class ContactFormController extends BasicController {
 	private DialogBoxController noUsersErrorCtr;
 	private ArrayList<String> myButtons;
 	private Panel main;
+	
+	private MailManager mailService;
 	/**
 	 * 
 	 * @param ureq
@@ -124,6 +128,7 @@ public class ContactFormController extends BasicController {
 		
 		//init email form
 		this.emailFrom = cmsg.getFrom();
+		mailService = CoreSpringFactory.getImpl(MailManager.class);
 		
 		cntctForm = new ContactForm(ureq, windowControl, emailFrom, isReadonly,isCanceable,hasRecipientsEditable);
 		listenTo(cntctForm);
@@ -206,40 +211,35 @@ public class ContactFormController extends BasicController {
 		}
 		else if (source == cntctForm) {
 			if (event == Event.DONE_EVENT) {
-				boolean useInstitutionalEmail = false;
-				Emailer emailer = new Emailer(emailFrom, useInstitutionalEmail);
 				//
 				boolean success = false;
 				try {
-					List<File> attachments = cntctForm.getAttachments();
+					File[] attachments = cntctForm.getAttachments();
 					//fxdiff VCRP-16: intern mail system		
 					MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-					success = emailer.sendEmail(context, cntctForm.getEmailToContactLists(), cntctForm.getSubject(), cntctForm.getBody(), attachments);
+					
+					MailBundle bundle = new MailBundle();
+					bundle.setContext(context);
+					bundle.setFromId(emailFrom);
+					bundle.setContactLists(cntctForm.getEmailToContactLists());
+					bundle.setContent(cntctForm.getSubject(), cntctForm.getBody(), attachments);
+					
+					MailerResult result = mailService.sendMessage(bundle);
+					success = result.isSuccessful();
 					if(cntctForm.isTcpFrom()) {
-						success = emailer.sendEmailCC(context, cntctForm.getEmailFrom(), cntctForm.getSubject(), cntctForm.getBody(), attachments);
+						
+						MailBundle ccBundle = new MailBundle();
+						ccBundle.setContext(context);
+						ccBundle.setFromId(emailFrom);
+						ccBundle.setCc(cntctForm.getEmailFrom());
+						ccBundle.setContent(cntctForm.getSubject(), cntctForm.getBody(), attachments);
+						
+						MailerResult ccResult = mailService.sendMessage(ccBundle);
+						success = ccResult.isSuccessful();
 					}
-				} catch (AddressException e) {
+				} catch (Exception e) {
 					//error in recipient email address(es)
 					handleAddressException(success);
-					//no return here, depending on boolean success there are
-					//events to fire
-				} catch (SendFailedException e) {
-					// error in sending message
-					// CAUSE: sender email address invalid
-					if(handleSendFailedException(e) ) {
-						// exception handling says that although the message could not be 
-						// send we should proceed and finish this workflow with a failed event
-						fireEvent(ureq, Event.FAILED_EVENT);
-						return;
-					} else {
-						fireEvent(ureq, Event.FAILED_EVENT);
-						return;
-					}
-				} catch (MessagingException e) {
-					// error in message-subject || .-body
-					handleMessagingException();
-					//fireEvent(ureq, Event.FAILED_EVENT);
-					return;
 				}
 				cntctForm.setDisplayOnly(true);
 				if (success) {
@@ -281,15 +281,6 @@ public class ContactFormController extends BasicController {
 		//
 	}
 
-	/**
-	 */
-	private void handleMessagingException() {
-		String infoMessage = translate("error.msg.send.nok");
-		infoMessage += "<br />";
-		infoMessage += translate("error.msg.content.nok");
-		this.getWindowControl().setError(infoMessage);
-	}
-
 	/**
 	 * @param success
 	 */
@@ -315,7 +306,7 @@ public class ContactFormController extends BasicController {
 	 * return boolean true: handling was successful, exception can be ignored; 
 	 * false: handling was not successful, refuse to proceed.
 	 */
-	private boolean handleSendFailedException(SendFailedException e) {
+	public boolean handleSendFailedException(SendFailedException e) {
 		//get wrapped excpetion
 		MessagingException me = (MessagingException) e.getNextException();
 		if (me instanceof AuthenticationFailedException) {
diff --git a/src/main/java/org/olat/notifications/NotificationsManagerImpl.java b/src/main/java/org/olat/notifications/NotificationsManagerImpl.java
index dbc6286cb50e90acf01f354a0b5984f7e518577c..0e2972f857972ef12542bb0970ab6ba5df1c9c14 100644
--- a/src/main/java/org/olat/notifications/NotificationsManagerImpl.java
+++ b/src/main/java/org/olat/notifications/NotificationsManagerImpl.java
@@ -42,7 +42,6 @@ import javax.persistence.EntityManager;
 import javax.persistence.LockModeType;
 import javax.persistence.TypedQuery;
 
-import org.apache.velocity.VelocityContext;
 import org.hibernate.FlushMode;
 import org.olat.ControllerFactory;
 import org.olat.core.CoreSpringFactory;
@@ -65,9 +64,9 @@ import org.olat.core.util.event.EventFactory;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.event.MultiUserEvent;
 import org.olat.core.util.i18n.I18nManager;
-import org.olat.core.util.mail.MailTemplate;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.notifications.NotificationHelper;
 import org.olat.core.util.notifications.NotificationsHandler;
 import org.olat.core.util.notifications.NotificationsManager;
@@ -501,19 +500,13 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us
 			}
 			plaintext.append("\n\n");
 		}
-		String mailText = plaintext.toString();
-		MailTemplate mailTempl = new MailTemplate(title, mailText, null) {
 
-			@Override
-			public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-			// nothing to do
-			}
-		};
-		
 		MailerResult result = null;
 		try {
-			// fxdiff VCRP-16: intern mail system
-			result = MailerWithTemplate.getInstance().sendRealMail(to, mailTempl);
+			MailBundle bundle = new MailBundle();
+			bundle.setToId(to);
+			bundle.setContent(title, plaintext.toString());
+			result = CoreSpringFactory.getImpl(MailManager.class).sendExternMessage(bundle, null);
 		} catch (Exception e) {
 			// FXOLAT-294 :: sending the mail will throw nullpointer exception if To-Identity has no
 			// valid email-address!, catch it...
diff --git a/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java b/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java
index f7f262b25c07a0b0f67aa08b6ee69d6930ecf15c..1f4236161422fcb38d46944dba76cec6b2d6a6b0 100644
--- a/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java
+++ b/src/main/java/org/olat/portfolio/ui/structel/EPShareListController.java
@@ -25,9 +25,6 @@ import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
-import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
-
 import org.olat.admin.user.UserSearchController;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
@@ -60,11 +57,14 @@ import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.WebappHelper;
 import org.olat.core.util.mail.ContactList;
-import org.olat.core.util.mail.Emailer;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailerResult;
 import org.olat.group.BusinessGroup;
 import org.olat.group.model.BusinessGroupSelectionEvent;
 import org.olat.group.ui.main.SelectBusinessGroupController;
@@ -92,6 +92,7 @@ public class EPShareListController extends FormBasicController {
 	private final EPFrontendManager ePFMgr;
 	private final BaseSecurity securityManager;
 	private final UserManager userManager;
+	private final MailManager mailManager;
 	private final String[] targetKeys = EPMapPolicy.Type.names();
 	private final String[] targetValues = new String[targetKeys.length];
 
@@ -108,6 +109,7 @@ public class EPShareListController extends FormBasicController {
 		ePFMgr = CoreSpringFactory.getImpl(EPFrontendManager.class);
 		securityManager = BaseSecurityManager.getInstance();
 		userManager = UserManager.getInstance();
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		for(int i=targetKeys.length; i-->0; ) {
 			targetValues[i] = translate("map.share.to." + targetKeys[i]);
 		}
@@ -408,22 +410,24 @@ public class EPShareListController extends FormBasicController {
 			busLink = bCF.getAsURIString(cEList, true); 
 		}		
 		
-		Emailer mailer = new Emailer(ureq.getLocale());
 		boolean success = false;
 		try {
-			ArrayList<ContactList> clList = new ArrayList<ContactList>();
-			clList.add(contactList);
 			String first = getIdentity().getUser().getProperty(UserConstants.FIRSTNAME, null);
 			String last = getIdentity().getUser().getProperty(UserConstants.LASTNAME, null);
 			String sender = first + " " + last;
 			String[] bodyArgs = new String[]{busLink, sender};
-			//fxdiff VCRP-16: intern mail system
+
 			MailContext context = new MailContextImpl(map.getOlatResource(), null, getWindowControl().getBusinessControl().getAsString()); 
-			success = mailer.sendEmail(context, clList, translate("map.share.invitation.mail.subject"), translate("map.share.invitation.mail.body", bodyArgs), null);
-		} catch (AddressException e) {
+			MailBundle bundle = new MailBundle();
+			bundle.setContext(context);
+			bundle.setFrom(WebappHelper.getMailConfig("mailReplyTo"));
+			bundle.setContactList(contactList);
+			bundle.setContent(translate("map.share.invitation.mail.subject"), translate("map.share.invitation.mail.body", bodyArgs));
+
+			MailerResult result = mailManager.sendMessage(bundle);
+			success = result.isSuccessful();
+		} catch (Exception e) {
 			logError("Error on sending invitation mail to contactlist, invalid address.", e);
-		} catch (MessagingException e) {
-			logError("Error on sending invitation mail to contactlist", e);
 		}
 		if (success) {
 			showInfo("map.share.invitation.mail.success");
diff --git a/src/main/java/org/olat/registration/PwChangeController.java b/src/main/java/org/olat/registration/PwChangeController.java
index 0dc96daf286ee7df8357715f2e10c5733e268a98..6d72b5f3a8e346cd5f4c1d3c7cab48963ea29e46 100644
--- a/src/main/java/org/olat/registration/PwChangeController.java
+++ b/src/main/java/org/olat/registration/PwChangeController.java
@@ -29,10 +29,10 @@ import java.text.DateFormat;
 import java.util.Date;
 import java.util.Locale;
 
-import org.apache.velocity.VelocityContext;
 import org.olat.basesecurity.Authentication;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.BaseSecurityModule;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.UserRequest;
@@ -53,10 +53,10 @@ import org.olat.core.id.Preferences;
 import org.olat.core.id.UserConstants;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailHelper;
-import org.olat.core.util.mail.MailTemplate;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.user.UserManager;
 import org.olat.user.UserModule;
 
@@ -73,6 +73,7 @@ public class PwChangeController extends BasicController {
 	
 	private Panel pwarea;
 	private WizardInfoController wic;
+	private final MailManager mailManager;
 	private RegistrationManager rm = RegistrationManager.getInstance();
 	private String pwKey;
 	private PwChangeForm pwf;
@@ -97,6 +98,7 @@ public class PwChangeController extends BasicController {
 	//fxdiff FXOLAT-113: business path in DMZ
 	public PwChangeController(UserRequest ureq, WindowControl wControl, String initialEmail) {
 		super(ureq, wControl);
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		myContent = createVelocityContainer("pwchange");
 		wic = new WizardInfoController(ureq, 4);
 		myContent.put("pwwizard", wic.getInitialComponent());
@@ -187,8 +189,7 @@ public class PwChangeController extends BasicController {
 				// Email requested for tempkey save the fields somewhere
 				String emailOrUsername = emailOrUsernameCtr.getEmailOrUsername();
 				emailOrUsername = emailOrUsername.trim();
-				String body = null;
-				String subject = null;
+
 				// get remote address
 				String ip = ureq.getHttpReq().getRemoteAddr();
 				String today = DateFormat.getDateInstance(DateFormat.LONG, ureq.getLocale()).format(new Date());
@@ -226,19 +227,16 @@ public class PwChangeController extends BasicController {
 					TemporaryKey tk = rm.loadTemporaryKeyByEmail(emailAdress);
 					if (tk == null) tk = rm.createTemporaryKeyByEmail(emailAdress, ip, RegistrationManager.PW_CHANGE);
 					myContent.contextPut("pwKey", tk.getRegistrationKey());
-					body = userTrans.translate("pwchange.intro", new String[] { identity.getName() })
-							+ userTrans.translate("pwchange.body", new String[] { serverpath, tk.getRegistrationKey(),
-									I18nManager.getInstance().getLocaleKey(ureq.getLocale()) }) + SEPARATOR
-							+ userTrans.translate("reg.wherefrom", new String[] { serverpath, today, ip });
-					subject = userTrans.translate("pwchange.subject");
-					MailTemplate mailTempl = new MailTemplate(subject, body, null) {
-						@Override
-						public void putVariablesInMailContext(VelocityContext context, Identity recipient) {
-							// nothing to do
-						}
-					};
-					//fxdiff VCRP-16: intern mail system
-					MailerResult result = MailerWithTemplate.getInstance().sendRealMail(identity, mailTempl);
+					StringBuilder body = new StringBuilder();
+					body.append(userTrans.translate("pwchange.intro", new String[] { identity.getName() }))
+					    .append(userTrans.translate("pwchange.body", new String[] { serverpath, tk.getRegistrationKey(), I18nManager.getInstance().getLocaleKey(ureq.getLocale()) }))
+					    .append(SEPARATOR)
+					    .append(userTrans.translate("reg.wherefrom", new String[] { serverpath, today, ip }));
+		
+					MailBundle bundle = new MailBundle();
+					bundle.setToId(identity);
+					bundle.setContent(userTrans.translate("pwchange.subject"), body.toString());
+					MailerResult result = mailManager.sendExternMessage(bundle, null);
 					if(result.getReturnCode() == 0) {
 						getWindowControl().setInfo(translate("email.sent"));
 						// prepare next step
diff --git a/src/main/java/org/olat/registration/RegistrationController.java b/src/main/java/org/olat/registration/RegistrationController.java
index a7b57bf910c6df7b90c90363611324f5b62c00f6..54a0ee1555d250f984b8ad217d47cfb8a0974c6a 100644
--- a/src/main/java/org/olat/registration/RegistrationController.java
+++ b/src/main/java/org/olat/registration/RegistrationController.java
@@ -60,8 +60,9 @@ import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.manager.MailManager;
 import org.olat.dispatcher.LocaleNegotiator;
 import org.olat.user.UserManager;
 import org.olat.user.UserPropertiesConfig;
@@ -261,8 +262,8 @@ public class RegistrationController extends BasicController implements Activatea
 				String ip = ureq.getHttpReq().getRemoteAddr();
 				String body = null;
 				String today = DateFormat.getDateInstance(DateFormat.LONG, ureq.getLocale()).format(new Date());
-				MailManager mailM = MailManager.getInstance();
-				//TODO eMail Vorlagen
+				MailManager mailM = CoreSpringFactory.getImpl(MailManager.class);
+
 				String serverpath = Settings.getServerContextPathURI();
 				boolean isMailSent = false;
 				if (!foundUser) {
@@ -273,9 +274,15 @@ public class RegistrationController extends BasicController implements Activatea
 							new String[] { serverpath, tk.getRegistrationKey(), I18nManager.getInstance().getLocaleKey(ureq.getLocale()) })
 							+ SEPARATOR
 							+ getTranslator().translate("reg.wherefrom", new String [] { serverpath, today, ip });
+					
 					try {
-						MailerResult result = mailM.sendExternMessage(null, null, null, email, null, null, null, translate("reg.subject"), body, null, null);
-						if (MailerResult.OK == result.getReturnCode()) isMailSent = true;
+						MailBundle bundle = new MailBundle();
+						bundle.setTo(email);
+						bundle.setContent(translate("reg.subject"), body);
+						MailerResult result = mailM.sendExternMessage(bundle, null);
+						if (result.isSuccessful()) {
+							isMailSent = true;
+						}
 					} catch (Exception e) {
 						// nothing to do, emailSent flag is false, errors will be reported to user
 					}
@@ -286,8 +293,14 @@ public class RegistrationController extends BasicController implements Activatea
 					body = translate("login.body", identity.getName()) + SEPARATOR
 							+ getTranslator().translate("reg.wherefrom", new String[] { serverpath, today, ip });
 					try {
-						MailerResult result = mailM.sendExternMessage(null, null, null, email, null, null, null, translate("login.subject"), body, null, null);
-						if (MailerResult.OK == result.getReturnCode()) isMailSent = true;
+						MailBundle bundle = new MailBundle();
+						bundle.setTo(email);
+						bundle.setContent(translate("login.subject"), body);
+						
+						MailerResult result = mailM.sendExternMessage(bundle, null);
+						if (result.isSuccessful()) {
+							isMailSent = true;
+						}
 					} catch (Exception e) {
 						// nothing to do, emailSent flag is false, errors will be reported to user
 					}
diff --git a/src/main/java/org/olat/registration/RegistrationManager.java b/src/main/java/org/olat/registration/RegistrationManager.java
index dcbd7a8865ae90365f863ca2a848b1334abd6c43..ad0273a8c36d62ba234aa912ae561983d0fbf512 100644
--- a/src/main/java/org/olat/registration/RegistrationManager.java
+++ b/src/main/java/org/olat/registration/RegistrationManager.java
@@ -41,7 +41,6 @@ import org.olat.basesecurity.AuthHelper;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.DBFactory;
-import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
@@ -53,8 +52,8 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.manager.MailManager;
 import org.olat.properties.Property;
 import org.olat.properties.PropertyManager;
 
@@ -72,6 +71,7 @@ public class RegistrationManager extends BasicManager {
 	protected static final int PWCHANGE_WORKFLOW_STEPS = 4;
 	
 	private RegistrationModule registrationModule;
+	private MailManager mailManager;
 
 	private RegistrationManager() {
 		// singleton
@@ -84,6 +84,14 @@ public class RegistrationManager extends BasicManager {
 		return new RegistrationManager();
 	}
 	
+	/**
+	 * [used by Spring]
+	 * @param mailManager
+	 */
+	public void setMailManager(MailManager mailManager) {
+		this.mailManager = mailManager;
+	}
+
 	/**
 	 * [used by Spring]
 	 * @param registrationModule
@@ -192,13 +200,12 @@ public class RegistrationManager extends BasicManager {
 		Locale loc = I18nModule.getDefaultLocale();
 		String[] userParams = new  String[] {newIdentity.getName(), user.getProperty(UserConstants.FIRSTNAME, loc), user.getProperty(UserConstants.LASTNAME, loc), user.getProperty(UserConstants.EMAIL, loc),
 				user.getPreferences().getLanguage(), Settings.getServerconfig("server_fqdn") + WebappHelper.getServletContextPath() };
-		Translator trans = new PackageTranslator(Util.getPackageName(RegistrationManager.class), loc);
+		Translator trans = Util.createPackageTranslator(RegistrationManager.class, loc);
 		String subject = trans.translate("reg.notiEmail.subject", userParams);
 		String body = trans.translate("reg.notiEmail.body", userParams);
 		
-		//fxdiff VCRP-16: intern mail system
-		MimeMessage msg = MailManager.getInstance().createMimeMessage(from, to, null, null, body, subject, null, result);
-		MailManager.getInstance().sendMessage(msg, result);
+		MimeMessage msg = mailManager.createMimeMessage(from, to, null, null, body, subject, null, result);
+		mailManager.sendMessage(msg, result);
 		if (result.getReturnCode() != MailerResult.OK ) {
 			logError("Could not send registration notification message, MailerResult was ::" + result.getReturnCode(), null);			
 		}
diff --git a/src/main/java/org/olat/registration/_spring/registrationContext.xml b/src/main/java/org/olat/registration/_spring/registrationContext.xml
index 8bdc3d12806d1ea90d0c1177ecaf131e5bd3a373..8e695da425419552cc32354d1924c1df14221464 100644
--- a/src/main/java/org/olat/registration/_spring/registrationContext.xml
+++ b/src/main/java/org/olat/registration/_spring/registrationContext.xml
@@ -3,7 +3,7 @@
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
+  http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 	<!-- Registration module -->
 	<bean id="registrationModule" class="org.olat.registration.RegistrationModule" depends-on="i18nModule" >
@@ -42,6 +42,7 @@
 	
 	<bean id="selfRegistrationManager" class="org.olat.registration.RegistrationManager">
 		<property name="registrationModule" ref="registrationModule" />
+		<property name="mailManager" ref="mailManager"/>
 	</bean>
 
 	<bean id="registrationPresetUsername.byEmail"
diff --git a/src/main/java/org/olat/registration/restapi/RegistrationWebService.java b/src/main/java/org/olat/registration/restapi/RegistrationWebService.java
index 90145e48232ffc6c716b6c0153a87149335bdc28..27ebd98552c1aa3127a9599846d78b7142c1f920 100644
--- a/src/main/java/org/olat/registration/restapi/RegistrationWebService.java
+++ b/src/main/java/org/olat/registration/restapi/RegistrationWebService.java
@@ -46,8 +46,9 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.manager.MailManager;
 import org.olat.registration.RegistrationController;
 import org.olat.registration.RegistrationManager;
 import org.olat.registration.RegistrationModule;
@@ -103,7 +104,7 @@ public class RegistrationWebService {
 		Locale locale = getLocale(request);
 		Translator translator = getTranslator(locale);
 		
-		MailManager mailM = MailManager.getInstance();
+		MailManager mailM = CoreSpringFactory.getImpl(MailManager.class);
 		UserManager userManager = UserManager.getInstance();
 		RegistrationManager rm = RegistrationManager.getInstance();
 		
@@ -127,8 +128,11 @@ public class RegistrationWebService {
 					+ SEPARATOR
 					+ translator.translate("reg.wherefrom", new String [] { serverpath, today, ip });
 			try {
-				MailerResult result = mailM.sendExternMessage(null, null, null, email, null, null, null, translator.translate("reg.subject"), body, null, null);
-				if (MailerResult.OK == result.getReturnCode()) {
+				MailBundle bundle = new MailBundle();
+				bundle.setTo(email);
+				bundle.setContent(translator.translate("reg.subject"), body);
+				MailerResult result = mailM.sendExternMessage(null, null);
+				if (result.isSuccessful()) {
 					response = Response.ok();
 				} else {
 					response = Response.serverError().status(Status.INTERNAL_SERVER_ERROR);
diff --git a/src/main/java/org/olat/repository/RepositoryMailing.java b/src/main/java/org/olat/repository/RepositoryMailing.java
index 043ad49e4afde624d6a54a3f716688162fb979eb..73ee5883a150daa9c627f20dcfb73c6b84a56cd3 100644
--- a/src/main/java/org/olat/repository/RepositoryMailing.java
+++ b/src/main/java/org/olat/repository/RepositoryMailing.java
@@ -19,7 +19,6 @@
  */
 package org.olat.repository;
 
-import java.util.Collections;
 import java.util.Locale;
 
 import org.apache.velocity.VelocityContext;
@@ -34,12 +33,13 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.filter.FilterFactory;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailPackage;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.group.ui.main.MemberPermissionChangeEvent;
 
 /**
@@ -113,7 +113,7 @@ public class RepositoryMailing {
 	}
 
 	protected static void sendEmail(Identity ureqIdentity, Identity identity, RepositoryEntry re,
-			Type type, MailPackage mailing, MailerWithTemplate mailer) {
+			Type type, MailPackage mailing) {
 		
 		if(mailing != null && !mailing.isSendEmail()) {
 			return;
@@ -139,7 +139,12 @@ public class RepositoryMailing {
 		}
 
 		String metaId = mailing == null ? null : mailing.getUuid();
-		MailerResult result = mailer.sendMailAsSeparateMails(context, Collections.singletonList(identity), null, template, ureqIdentity, metaId);
+		MailerResult result = new MailerResult();
+		MailManager mailManager = CoreSpringFactory.getImpl(MailManager.class);
+		MailBundle bundle = mailManager.makeMailBundle(context, identity, template, ureqIdentity, metaId, result);
+		if(bundle != null) {
+			mailManager.sendMessage(bundle);
+		}
 		if(mailing != null) {
 			mailing.appendResult(result);
 		}
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index 23cffa66ab7ec7fe9392bc9ab4010687bda67991..2642906aedccd726e875d45808aadd214f90ddbd 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -75,7 +75,6 @@ import org.olat.core.util.ImageHelper;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.image.Size;
 import org.olat.core.util.mail.MailPackage;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.vfs.LocalFolderImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
@@ -127,8 +126,6 @@ public class RepositoryManager extends BasicManager {
 	private RepositoryModule repositoryModule;
 	@Autowired
 	private ACReservationDAO reservationDao;
-	@Autowired
-	private MailerWithTemplate mailer;
 
 	
 	/**
@@ -1930,12 +1927,12 @@ public class RepositoryManager extends BasicManager {
 						ResourceReservation reservation =
 								reservationDao.createReservation(identityToAdd, "repo_tutors", expiration, re.getOlatResource());
 						if(reservation != null) {
-							RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addTutor, mailing, mailer);
+							RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addTutor, mailing);
 						}
 					}
 				} else {
 					addInternalTutors(ureqIdentity, identityToAdd, re, reallyAddedId);
-					RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addTutor, mailing, mailer);
+					RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addTutor, mailing);
 				}
 
 			}//else silently ignore already owner identities
@@ -2021,13 +2018,13 @@ public class RepositoryManager extends BasicManager {
 						ResourceReservation reservation =
 								reservationDao.createReservation(identityToAdd, "repo_participant", expiration, re.getOlatResource());
 						if(reservation != null) {
-							RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addParticipant, mailing, mailer);
+							RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addParticipant, mailing);
 						}
 					}
 				} else {
 					addInternalParticipant(ureqIdentity, identityToAdd, re);
 					reallyAddedId.add(identityToAdd);
-					RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addParticipant, mailing, mailer);
+					RepositoryMailing.sendEmail(ureqIdentity, identityToAdd, re, RepositoryMailing.Type.addParticipant, mailing);
 				}
 			}
 		}
@@ -2067,7 +2064,7 @@ public class RepositoryManager extends BasicManager {
     	securityManager.removeIdentityFromSecurityGroup(identity, re.getParticipantGroup());
 
     	if(sendMail) {
-    		RepositoryMailing.sendEmail(ureqIdentity, identity, re, RepositoryMailing.Type.removeParticipant, mailing, mailer);
+    		RepositoryMailing.sendEmail(ureqIdentity, identity, re, RepositoryMailing.Type.removeParticipant, mailing);
     	}
 
 			ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType();
@@ -2138,7 +2135,7 @@ public class RepositoryManager extends BasicManager {
 		}
 		
 		for(Identity identity:members) {
-			RepositoryMailing.sendEmail(ureqIdentity, identity, re, RepositoryMailing.Type.removeParticipant, mailing, mailer);
+			RepositoryMailing.sendEmail(ureqIdentity, identity, re, RepositoryMailing.Type.removeParticipant, mailing);
 		}
 		return allOk;
 	}
diff --git a/src/main/java/org/olat/repository/_spring/repositoryContext.xml b/src/main/java/org/olat/repository/_spring/repositoryContext.xml
index 9f1785e6a85a8661f49f109da86f10d64c3ead43..e4bdede3c67dd2495bff8da989c4fbc0ff6e1188 100644
--- a/src/main/java/org/olat/repository/_spring/repositoryContext.xml
+++ b/src/main/java/org/olat/repository/_spring/repositoryContext.xml
@@ -61,6 +61,7 @@
 	<bean id="repositoryDeletionManager"
 		class="org.olat.repository.delete.service.RepositoryDeletionManager">
 		<constructor-arg index="0" ref="deletionModule" />
+		<property name="mailManager" ref="mailManager" />
 	</bean>
 	
 	<!-- vitero admin. panel -->
diff --git a/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java b/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java
index 5b1bc59150934ed49a4152a819eadff8a3a6cf47..a551772150dfe5482184ce40603d9e7145b3d060 100644
--- a/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java
+++ b/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java
@@ -26,6 +26,7 @@ package org.olat.repository.controllers;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 import org.apache.velocity.VelocityContext;
 import org.olat.basesecurity.BaseSecurity;
@@ -56,13 +57,14 @@ import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.UserConstants;
+import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
 import org.olat.core.util.mail.MailNotificationEditController;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
+import org.olat.core.util.mail.MailManager;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.group.BusinessGroup;
@@ -96,11 +98,13 @@ public class WizardCloseCourseController extends WizardController implements Wiz
 	private CloseRessourceOptionForm formStep2;
 	
 	private final BusinessGroupService businessGroupService;
+	private final MailManager mailManager;
 	
 	public WizardCloseCourseController(UserRequest ureq, WindowControl control, RepositoryEntry repositoryEntry) {
 		super(ureq, control, NUM_STEPS);
 		setBasePackage(RepositoryManager.class);
 		this.repositoryEntry = repositoryEntry;
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
 
 		mainVc = createVelocityContainer("wizard");
@@ -193,20 +197,21 @@ public class WizardCloseCourseController extends WizardController implements Wiz
 				if (securityManager.isIdentityInSecurityGroup(ureq.getIdentity(), owners)) {
 					ownerList = securityManager.getIdentitiesOfSecurityGroup(owners);
 				}
-				List<Identity> ccIdentities = new ArrayList<Identity>();
-				if (mailNotificationCtr.getMailTemplate().getCpfrom()) {
-					ccIdentities.add(ureq.getIdentity());
-				} else {
-					ccIdentities = null;
-				}
-				//fxdiff VCRP-16: intern mail system
+
 				String businessPath = getWindowControl().getBusinessControl().getAsString();
 				MailContext context = new MailContextImpl(businessPath);
-				MailerResult mailerResult = MailerWithTemplate.getInstance().sendMailAsSeparateMails(context, ownerList, ccIdentities,
-						mailNotificationCtr.getMailTemplate(), ureq.getIdentity());
+				String metaId = UUID.randomUUID().toString().replace("-", "");
+				MailerResult result = new MailerResult();
+				MailBundle[] bundles = mailManager.makeMailBundles(context, ownerList, mailNotificationCtr.getMailTemplate(), ureq.getIdentity(), metaId, result);
+				result.append(mailManager.sendMessage(bundles));
+				if (mailNotificationCtr.getMailTemplate().getCpfrom()) {
+					MailBundle ccBundle = mailManager.makeMailBundle(context, ureq.getIdentity(), mailNotificationCtr.getMailTemplate(), ureq.getIdentity(), metaId, result);
+					result.append(mailManager.sendMessage(ccBundle));
+				}
+				
 				StringBuilder errorMessage = new StringBuilder();
 				StringBuilder warningMessage = new StringBuilder();
-				MailHelper.appendErrorsAndWarnings(mailerResult, errorMessage, warningMessage, ureq.getLocale());
+				MailHelper.appendErrorsAndWarnings(result, errorMessage, warningMessage, ureq.getLocale());
 				if (warningMessage.length() > 0) getWindowControl().setWarning(warningMessage.toString());
 				if (errorMessage.length() > 0) getWindowControl().setError(errorMessage.toString());
 				ownerList.clear();
diff --git a/src/main/java/org/olat/repository/delete/service/RepositoryDeletionManager.java b/src/main/java/org/olat/repository/delete/service/RepositoryDeletionManager.java
index b1f04b10f7980a81d6ab6ef74f73cf1ebeb5df15..ba132cb8443092504a5a755cfd9117025287be59 100644
--- a/src/main/java/org/olat/repository/delete/service/RepositoryDeletionManager.java
+++ b/src/main/java/org/olat/repository/delete/service/RepositoryDeletionManager.java
@@ -28,7 +28,6 @@ package org.olat.repository.delete.service;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -48,9 +47,10 @@ import org.olat.core.id.UserConstants;
 import org.olat.core.manager.BasicManager;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
-import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.properties.Property;
 import org.olat.properties.PropertyManager;
 import org.olat.repository.RepositoryEntry;
@@ -87,6 +87,8 @@ public class RepositoryDeletionManager extends BasicManager implements UserDataD
 	public static final String SEND_DELETE_EMAIL_ACTION = "sendDeleteEmail";
 	private static final String REPOSITORY_DELETED_ACTION = "respositoryEntryDeleted";
 	private DeletionModule deletionModule;
+	private MailManager mailManager;
+	
 
 	/**
 	 * [used by spring]
@@ -96,7 +98,14 @@ public class RepositoryDeletionManager extends BasicManager implements UserDataD
 		this.deletionModule = deletionModule;
 		INSTANCE = this;
 	}
-
+	
+	/**
+	 * [used by Spring]
+	 * @param mailManager
+	 */
+	public void setMailManager(MailManager mailManager) {
+		this.mailManager = mailManager;
+	}
 
 	/**
 	 * @return Singleton.
@@ -223,7 +232,6 @@ public class RepositoryDeletionManager extends BasicManager implements UserDataD
 
 	private String sendEmailToIdentity(Identity identity, Map<Identity, List<RepositoryEntry>> identityRepositoryList, MailTemplate template, 
 			boolean isTemplateChanged, String keyEmailSubject, String keyEmailBody, Identity sender, Translator pT) {
-		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 		template.addToContext("responseTo", deletionModule.getEmailResponseTo());
 		if (!isTemplateChanged) {
 			// Email template has NOT changed => take translated version of subject and body text
@@ -241,14 +249,17 @@ public class RepositoryDeletionManager extends BasicManager implements UserDataD
 		template.addToContext("repositoryList", buf.toString());
 		template.putVariablesInMailContext(template.getContext(), identity);
 		logDebug(" Try to send Delete-email to identity=" + identity.getName() + " with email=" + identity.getUser().getProperty(UserConstants.EMAIL, null));
-		List<Identity> ccIdentities = new ArrayList<Identity>();
+
+		
+		MailerResult result = new MailerResult();
+		MailBundle bundle = mailManager.makeMailBundle(null, identity, template, sender, null, result);
+		result.append(mailManager.sendMessage(bundle));
 		if(template.getCpfrom()) {
-			ccIdentities.add(sender);
-		} else {
-			ccIdentities = null;	
+			MailBundle ccBundle = mailManager.makeMailBundle(null, sender, template, sender, null, result);
+			result.append(mailManager.sendMessage(ccBundle));
 		}
-		MailerResult mailerResult = mailer.sendMailAsSeparateMails(null, Collections.singletonList(identity), ccIdentities, template, sender);
-		if (mailerResult.getReturnCode() == MailerResult.OK) {
+		
+		if (result.getReturnCode() == MailerResult.OK) {
 			// Email sended ok => set deleteEmailDate
 			for (Iterator<RepositoryEntry> repoIterator = identityRepositoryList.get(identity).iterator(); repoIterator.hasNext();) {
 				RepositoryEntry repositoryEntry = repoIterator.next();
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_9_0_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_9_0_0.java
index e9954fa25249d2d4950ae4820ffff39f7eca5bb0..621e435c07767e88ac29ba6bbe46c95a17c7ed59 100644
--- a/src/main/java/org/olat/upgrade/OLATUpgrade_9_0_0.java
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_9_0_0.java
@@ -30,9 +30,7 @@ import java.util.zip.CheckedInputStream;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.output.NullOutputStream;
 import org.olat.core.commons.persistence.DB;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
-import org.olat.core.util.mail.manager.MailManager;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.upgrade.model.DBMailAttachmentData;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -45,8 +43,6 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class OLATUpgrade_9_0_0 extends OLATUpgrade {
 	
-	private static final OLog log = Tracing.createLoggerFor(OLATUpgrade_9_0_0.class);
-	
 	private static final int BATCH_SIZE = 20;
 	private static final String TASK_MAILS = "Upgrade mails";
 	private static final String VERSION = "OLAT_9.0.0";
diff --git a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
index ae24dfc0839339e1f0798f79e67ccdde40a8f51f..93241be586ece73c8701e72660434183bb2f9324 100644
--- a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
@@ -52,6 +52,10 @@
 					<constructor-arg index="0" value="OLAT_9.0.0" />
 					<property name="alterDbStatements" value="alter_8_4_0_to_9_0_0.sql" />
 				</bean>
+				<bean id="database_upgrade_9_1_0" class="org.olat.upgrade.DatabaseUpgrade">
+					<constructor-arg index="0" value="OLAT_9.1.0" />
+					<property name="alterDbStatements" value="alter_9_0_0_to_9_1_0.sql" />
+				</bean>
 			</list>
 		</property>
 	</bean>
diff --git a/src/main/java/org/olat/user/ProfileAndHomePageEditController.java b/src/main/java/org/olat/user/ProfileAndHomePageEditController.java
index ad7a8bfe03255e4639d514b583709e83066b88d8..530ba8458d136bc2b7c3d3a256fe6a03be57f417 100644
--- a/src/main/java/org/olat/user/ProfileAndHomePageEditController.java
+++ b/src/main/java/org/olat/user/ProfileAndHomePageEditController.java
@@ -30,13 +30,11 @@ import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
-
-import javax.mail.MessagingException;
-import javax.mail.SendFailedException;
-import javax.mail.internet.AddressException;
+import java.util.Map;
 
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.BaseSecurityModule;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -54,12 +52,14 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
 import org.olat.core.id.User;
-import org.olat.core.logging.Tracing;
 import org.olat.core.util.Util;
+import org.olat.core.util.WebappHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.SyncerExecutor;
 import org.olat.core.util.event.MultiUserEvent;
-import org.olat.core.util.mail.Emailer;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailerResult;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.login.SupportsAfterLoginInterceptor;
 import org.olat.registration.RegistrationManager;
@@ -96,6 +96,7 @@ public class ProfileAndHomePageEditController extends BasicController implements
 	protected Identity identityToModify;
 	protected HomePageConfig homePageConfig;
 	private DialogBoxController dialogCtr;
+	private final MailManager mailManager;
 	private RegistrationManager rm = RegistrationManager.getInstance();
 	private static String SEPARATOR = "\n____________________________________________________________________\n";
 
@@ -121,6 +122,7 @@ public class ProfileAndHomePageEditController extends BasicController implements
 		this.isAdministrativeUser = isAdministrativeUser;
 		this.translator = Util.createPackageTranslator(ProfileAndHomePageEditController.class, ureq.getLocale());
 		this.translator = UserManager.getInstance().getPropertyHandlerTranslator(this.translator);
+		mailManager = CoreSpringFactory.getImpl(MailManager.class);
 
 		this.myContent = new VelocityContainer("homepage", VELOCITY_ROOT + "/homepage.html", this.translator, this);
 		this.previewButton = LinkFactory.createButtonSmall("command.preview", this.myContent, this);
@@ -272,10 +274,10 @@ public class ProfileAndHomePageEditController extends BasicController implements
 		// mailer configuration
 		String serverpath = Settings.getServerContextPathURI();
 		String servername = ureq.getHttpReq().getServerName();
-		Emailer mailer = new Emailer(ureq.getLocale());
-		Tracing.createLoggerFor(ProfileAndHomePageEditController.class).debug("this servername is " + servername + " and serverpath is " + serverpath);
+
+		logDebug("this servername is " + servername + " and serverpath is " + serverpath, null);
 		// load or create temporary key
-		HashMap<String, String> mailMap = new HashMap<String, String>();
+		Map<String, String> mailMap = new HashMap<String, String>();
 		mailMap.put("currentEMail", currentEmail);
 		mailMap.put("changedEMail", changedEmail);
 		
@@ -301,7 +303,14 @@ public class ProfileAndHomePageEditController extends BasicController implements
 		subject = translate("email.change.subject");
 		// send email
 		try {
-			boolean isMailSent = mailer.sendEmail(changedEmail, subject, body);
+			
+			MailBundle bundle = new MailBundle();
+			bundle.setFrom(WebappHelper.getMailConfig("mailReplyTo"));
+			bundle.setTo(changedEmail);
+			bundle.setContent(subject, body);
+
+			MailerResult result = mailManager.sendMessage(bundle);
+			boolean isMailSent = result.isSuccessful();
 			if (isMailSent) {
 				tk.setMailSent(true);
 				// set key
@@ -314,15 +323,9 @@ public class ProfileAndHomePageEditController extends BasicController implements
 				rm.deleteTemporaryKeyWithId(tk.getRegistrationKey());
 				getWindowControl().setError(this.translator.translate("email.notsent"));
 			}
-		} catch (AddressException e) {
-			rm.deleteTemporaryKeyWithId(tk.getRegistrationKey());
-			getWindowControl().setError(this.translator.translate("email.notsent"));
-		} catch (SendFailedException e) {
-			rm.deleteTemporaryKeyWithId(tk.getRegistrationKey());
-			getWindowControl().setError(this.translator.translate("email.notsent"));
-		} catch (MessagingException e) {
+		} catch (Exception e) {
 			rm.deleteTemporaryKeyWithId(tk.getRegistrationKey());
-			getWindowControl().setError(this.translator.translate("email.notsent"));
+			getWindowControl().setError(translator.translate("email.notsent"));
 		}
 	}
 
diff --git a/src/main/java/org/olat/user/_spring/userContext.xml b/src/main/java/org/olat/user/_spring/userContext.xml
index f4cc883ed9d8f6a27ffab03daaed5a8ae1492cd4..a4f8cd577095c78839d9160b714aee6a6884e18b 100644
--- a/src/main/java/org/olat/user/_spring/userContext.xml
+++ b/src/main/java/org/olat/user/_spring/userContext.xml
@@ -289,6 +289,7 @@
 		<constructor-arg index="0" ref="deletionModule" />
 		<constructor-arg index="1" ref="coordinatorManager" />
 		<property name="baseSecurityManager" ref="baseSecurityManager" />
+		<property name="mailManager" ref="mailManager"/>
 		<property name="keepUserLoginAfterDeletion" value="${keepUserLoginAfterDeletion}" />
 		<property name="keepUserEmailAfterDeletion" value="${keepUserEmailAfterDeletion}" />
 	</bean>
diff --git a/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java b/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java
index 742b9bf156ae8d6afdb1eda5ac4f4519c4f31db4..ed76cc82270cbe8cb893003f0ed73188969ac1be 100644
--- a/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java
+++ b/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java
@@ -19,7 +19,6 @@
  */
 package org.olat.core.util.mail.manager;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -32,6 +31,8 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.MailBoxExtension;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailModule;
 import org.olat.core.util.mail.MailerResult;
 import org.olat.core.util.mail.model.DBMailLight;
@@ -79,8 +80,13 @@ public class MailManagerTest extends OlatTestCase {
 	public void testCreateEmail() {
 		Identity fromId = JunitTestHelper.createAndPersistIdentityAsUser("mail-1-" + UUID.randomUUID().toString());
 		Identity toId = JunitTestHelper.createAndPersistIdentityAsUser("mail-2-" + UUID.randomUUID().toString());
+		
+		MailBundle bundle = new MailBundle();
+		bundle.setFromId(fromId);
+		bundle.setToId(toId);
+		bundle.setContent("Hello", "Hello world");
 
-		MailerResult result = mailManager.sendMessage(null, fromId, null, toId, null, null, null, null, null, "Hello", "Hello world", null);
+		MailerResult result = mailManager.sendMessage(bundle);
 		Assert.assertNotNull(result);
 		Assert.assertEquals(MailerResult.OK, result.getReturnCode());
 	}
@@ -90,7 +96,13 @@ public class MailManagerTest extends OlatTestCase {
 		//send a mail
 		Identity fromId = JunitTestHelper.createAndPersistIdentityAsUser("mail-3-" + UUID.randomUUID().toString());
 		Identity toId = JunitTestHelper.createAndPersistIdentityAsUser("mail-4-" + UUID.randomUUID().toString());
-		MailerResult result = mailManager.sendMessage(null, fromId, null, toId, null, null, null, null, null, "Hello inbox", "Content of inbox", null);
+		
+		MailBundle bundle = new MailBundle();
+		bundle.setFromId(fromId);
+		bundle.setToId(toId);
+		bundle.setContent("Hello inbox", "Content of inbox");
+
+		MailerResult result = mailManager.sendMessage(bundle);
 		Assert.assertNotNull(result);
 		Assert.assertEquals(MailerResult.OK, result.getReturnCode());
 		dbInstance.commitAndCloseSession();
@@ -110,7 +122,13 @@ public class MailManagerTest extends OlatTestCase {
 		//send a mail
 		Identity fromId = JunitTestHelper.createAndPersistIdentityAsUser("mail-5-" + UUID.randomUUID().toString());
 		Identity toId = JunitTestHelper.createAndPersistIdentityAsUser("mail-6-" + UUID.randomUUID().toString());
-		MailerResult result = mailManager.sendMessage(null, fromId, null, toId, null, null, null, null, null, "Hello outbox", "Content of outbox", null);
+		
+		MailBundle bundle = new MailBundle();
+		bundle.setFromId(fromId);
+		bundle.setToId(toId);
+		bundle.setContent("Hello outbox","Content of outbox");
+		
+		MailerResult result = mailManager.sendMessage(bundle);
 		Assert.assertNotNull(result);
 		Assert.assertEquals(MailerResult.OK, result.getReturnCode());
 		dbInstance.commitAndCloseSession();
@@ -133,7 +151,13 @@ public class MailManagerTest extends OlatTestCase {
 		Identity toId = JunitTestHelper.createAndPersistIdentityAsUser("mail-6-" + UUID.randomUUID().toString());
 		dbInstance.commitAndCloseSession();
 		
-		MailerResult result = mailManager.sendMessage(null, fromId, null, toId, null, null, null, null, metaId, "Hello meta ID", "Meta ID", null);
+		MailBundle bundle = new MailBundle();
+		bundle.setFromId(fromId);
+		bundle.setToId(toId);
+		bundle.setMetaId(metaId);
+		bundle.setContent("Hello meta ID", "Meta ID");
+		
+		MailerResult result = mailManager.sendMessage(bundle);
 		Assert.assertNotNull(result);
 		Assert.assertEquals(MailerResult.OK, result.getReturnCode());
 		dbInstance.commitAndCloseSession();
@@ -150,7 +174,7 @@ public class MailManagerTest extends OlatTestCase {
 	
 	
 	@Test
-	public void testSendCC() {
+	public void testSend_BCC() {
 		//send a mail to three ids
 		Identity fromId = JunitTestHelper.createAndPersistIdentityAsUser("mail-7-" + UUID.randomUUID().toString());
 		Identity toId_1 = JunitTestHelper.createAndPersistIdentityAsUser("mail-8-" + UUID.randomUUID().toString());
@@ -161,8 +185,13 @@ public class MailManagerTest extends OlatTestCase {
 		ccs.add(toId_1);
 		ccs.add(toId_2);
 		ccs.add(toId_3);
-		List<ContactList> ccList = Collections.singletonList(ccs);
-		MailerResult result = mailManager.sendMessage(null, fromId, null, null, null, null, null, ccList, null, "Hello ccList", "Content of ccList", null);
+
+		MailBundle bundle = new MailBundle();
+		bundle.setFromId(fromId);
+		bundle.setContactList(ccs);
+		bundle.setContent("Hello ccList", "Content of ccList");
+		
+		MailerResult result = mailManager.sendMessage(bundle);
 		Assert.assertNotNull(result);
 		Assert.assertEquals(MailerResult.OK, result.getReturnCode());
 		dbInstance.commitAndCloseSession();
@@ -202,8 +231,14 @@ public class MailManagerTest extends OlatTestCase {
 		ccs.add(toId_2);
 		ccs.add(toId_3);
 		ccs.add(fromId);
-		List<ContactList> ccList = Collections.singletonList(ccs);
-		MailerResult result = mailManager.sendMessage(null, fromId, null, null, null, null, null, ccList, metaId, "Hello delList", "Content of delList", null);
+		
+		MailBundle bundle = new MailBundle();
+		bundle.setFromId(fromId);
+		bundle.setContactList(ccs);
+		bundle.setMetaId(metaId);
+		bundle.setContent("Hello delList", "Content of delList");
+		
+		MailerResult result = mailManager.sendMessage(bundle);
 		Assert.assertNotNull(result);
 		Assert.assertEquals(MailerResult.OK, result.getReturnCode());
 		dbInstance.commitAndCloseSession();
@@ -243,13 +278,33 @@ public class MailManagerTest extends OlatTestCase {
 		Identity toId_2 = JunitTestHelper.createAndPersistIdentityAsUser("mail-9-" + UUID.randomUUID().toString());
 		Identity toId_3 = JunitTestHelper.createAndPersistIdentityAsUser("mail-10-" + UUID.randomUUID().toString());
 		
-		MailerResult result1 = mailManager.sendMessage(null, fromId, null, toId_1, null, null, null, null, metaId, "Hello ccList", "Content of ccList", null);
+		MailBundle bundle_1 = new MailBundle();
+		bundle_1.setFromId(fromId);
+		bundle_1.setToId(toId_1);
+		bundle_1.setMetaId(metaId);
+		bundle_1.setContent("Hello ccList", "Content of ccList");
+		
+		MailerResult result1 = mailManager.sendMessage(bundle_1);
 		Assert.assertNotNull(result1);
 		Assert.assertEquals(MailerResult.OK, result1.getReturnCode());
-		MailerResult result2 = mailManager.sendMessage(null, fromId, null, toId_2, null, null, null, null, metaId, "Hello ccList", "Content of ccList", null);
+		
+		MailBundle bundle_2 = new MailBundle();
+		bundle_2.setFromId(fromId);
+		bundle_2.setToId(toId_2);
+		bundle_2.setMetaId(metaId);
+		bundle_2.setContent("Hello ccList", "Content of ccList");
+		
+		MailerResult result2 = mailManager.sendMessage(bundle_2);
 		Assert.assertNotNull(result2);
 		Assert.assertEquals(MailerResult.OK, result2.getReturnCode());
-		MailerResult result3 = mailManager.sendMessage(null, fromId, null, toId_3, null, null, null, null, metaId, "Hello ccList", "Content of ccList", null);
+		
+		MailBundle bundle_3 = new MailBundle();
+		bundle_3.setFromId(fromId);
+		bundle_3.setToId(toId_3);
+		bundle_3.setMetaId(metaId);
+		bundle_3.setContent("Hello ccList", "Content of ccList");
+		
+		MailerResult result3 = mailManager.sendMessage(bundle_3);
 		Assert.assertNotNull(result3);
 		Assert.assertEquals(MailerResult.OK, result3.getReturnCode());
 		dbInstance.commitAndCloseSession();
diff --git a/src/test/java/org/olat/core/util/mail/MailTest.java b/src/test/java/org/olat/core/util/mail/manager/MailTest.java
similarity index 80%
rename from src/test/java/org/olat/core/util/mail/MailTest.java
rename to src/test/java/org/olat/core/util/mail/manager/MailTest.java
index 6bea908aa2978311d146005a28e1b900077032ea..8f45663bf5e292330430980d7b23c99d5fbf5ffe 100644
--- a/src/test/java/org/olat/core/util/mail/MailTest.java
+++ b/src/test/java/org/olat/core/util/mail/manager/MailTest.java
@@ -23,7 +23,7 @@
 * under the Apache 2.0 license as the original file.  
 * <p>
 */
-package org.olat.core.util.mail;
+package org.olat.core.util.mail.manager;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -43,8 +43,15 @@ import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
+import org.olat.core.util.mail.MailBundle;
+import org.olat.core.util.mail.MailContext;
+import org.olat.core.util.mail.MailHelper;
+import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailTemplate;
+import org.olat.core.util.mail.MailerResult;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
 	
 /**
  * Description:<br>
@@ -56,7 +63,10 @@ import org.olat.test.OlatTestCase;
  *         http://www.frentix.com
  */
 public class MailTest extends OlatTestCase {
-	private Identity id1, id2, id3, id4, id5, id6;
+	private Identity id1, id2, id3, id4, id6;
+	
+	@Autowired
+	private MailManager mailManager;
 
 	// for local debugging you can set a systemproperty to a maildomain where
 	// you immediately get the mails. If the property is not set the
@@ -78,7 +88,6 @@ public class MailTest extends OlatTestCase {
 		id2 = JunitTestHelper.createAndPersistIdentityAsUser("two");
 		id3 = JunitTestHelper.createAndPersistIdentityAsUser("three");
 		id4 = JunitTestHelper.createAndPersistIdentityAsUser("four");
-		id5 = JunitTestHelper.createAndPersistIdentityAsUser("five");
 		id6 = JunitTestHelper.createAndPersistIdentityAsUser("six");
 	}
 
@@ -130,50 +139,50 @@ public class MailTest extends OlatTestCase {
 		context.put("foo", "bar");
 		String template = "foo $foo";
 		MailerResult result = new MailerResult();
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 		assertEquals("foo bar", writer.toString());
 
 		writer = new StringWriter();
 		template = "foo foo";
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 		assertEquals("foo foo", writer.toString());
 
 		writer = new StringWriter();
 		template = "foo $$foo";
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 		assertEquals("foo $bar", writer.toString());
 
 		writer = new StringWriter();
 		template = "foo $ foo";
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 		assertEquals("foo $ foo", writer.toString());
 
 		writer = new StringWriter();
 		template = "foo $ foo";
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 		assertEquals("foo $ foo", writer.toString());
 
 		writer = new StringWriter();
 		template = "foo #foo \n##sdf jubla";
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 		assertEquals("foo #foo \n", writer.toString());
 
 		writer = new StringWriter();
 		template = "foo #if(true)\n#end";
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 		assertEquals("foo ", writer.toString());
 
 		// illegal templates: unclosed if-else statement
 		writer = new StringWriter();
 		template = "foo #if";
-		MailerWithTemplate.getInstance().evaluate(context, template, writer, result);
+		((MailManagerImpl)mailManager).evaluate(context, template, writer, result);
 		assertEquals(MailerResult.TEMPLATE_PARSE_ERROR, result.getReturnCode());
 		assertEquals("", writer.toString());
 	}
@@ -208,20 +217,16 @@ public class MailTest extends OlatTestCase {
 		recipients.add(id1);
 		recipients.add(id2);
 		recipients.add(id3);
-		List<Identity> recipientsCC = new ArrayList<Identity>();
-		recipientsCC.add(id4);
-		recipientsCC.add(id5);
-		List<Identity> recipientsBCC = new ArrayList<Identity>();
-		recipientsBCC.add(id6);
+		Identity recipientCC = id4;
 
 		// tests with / witthout CC and BCC
 
 		MailerResult result = new MailerResult();
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
 		assertEquals(MailerResult.OK, result.getReturnCode());
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, recipientsCC, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, recipientCC, template, id6, null);
 		assertEquals(MailerResult.OK, result.getReturnCode());
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 	}
 
@@ -253,20 +258,16 @@ public class MailTest extends OlatTestCase {
 		recipients.add(id1);
 		recipients.add(id2);
 		recipients.add(id3);
-		List<Identity> recipientsCC = new ArrayList<Identity>();
-		recipientsCC.add(id4);
-		recipientsCC.add(id5);
-		List<Identity> recipientsBCC = new ArrayList<Identity>();
-		recipientsBCC.add(id6);
+		Identity recipientCC = id4;
 
 		// tests with / witthout CC and BCC
 
 		MailerResult result = new MailerResult();
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
 		assertEquals(MailerResult.OK, result.getReturnCode());
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, recipientsCC, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, recipientCC, template, id6, null);
 		assertEquals(MailerResult.OK, result.getReturnCode());
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 	}
 
@@ -307,7 +308,7 @@ public class MailTest extends OlatTestCase {
 		recipients.add(id1);
 
 		MailerResult result = new MailerResult();
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id2);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id2, null);
 		assertEquals(MailerResult.OK, result.getReturnCode());
 	}
 
@@ -336,7 +337,7 @@ public class MailTest extends OlatTestCase {
 		recipients.add(id1);
 
 		MailerResult result = new MailerResult();
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id2);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id2, null);
 		assertEquals(MailerResult.ATTACHMENT_INVALID, result.getReturnCode());
 	}
 
@@ -365,50 +366,65 @@ public class MailTest extends OlatTestCase {
 		DBFactory.getInstance().intermediateCommit();
 
 		List<Identity> recipients = new ArrayList<Identity>();
-		List<Identity> recipientsCC = new ArrayList<Identity>();
+
 
 		recipients.add(illegal1);
 
 		// if only one recipient: error must be indicated
 		MailerResult result = new MailerResult();
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
 		// mail will bounce back since address does not exist, but sent to local MTA
 		// this test is not very good, depends on smtp settings!
 		//assertEquals(MailerResult.OK, result.getReturnCode());
 
 		recipients = new ArrayList<Identity>();
 		recipients.add(illegal2);
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
 		// mail will bounce back since address does not exist, but sent to local MTA
 		assertEquals(MailerResult.OK, result.getReturnCode());
 
 		recipients = new ArrayList<Identity>();
 		recipients.add(illegal3);
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
 		assertEquals(MailerResult.RECIPIENT_ADDRESS_ERROR, result.getReturnCode());
 
 		// now with one valid and the invalid recipient: should return ok but have
 		// one recipient in the failed list
 		recipients.add(id1);
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, id6);
-		assertEquals(MailerResult.OK, result.getReturnCode());
+		result = sendMailAsSeparateMails(null, recipients, null, template, id6, null);
+		assertEquals(MailerResult.RECIPIENT_ADDRESS_ERROR, result.getReturnCode());
 		assertEquals(1, result.getFailedIdentites().size());
 
 		// valid recipient but invalid sender
 		recipients = new ArrayList<Identity>();
 		recipients.add(id1);
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, null, template, illegal3);
+		result = sendMailAsSeparateMails(null, recipients, null, template, illegal3, null);
 		assertEquals(MailerResult.SENDER_ADDRESS_ERROR, result.getReturnCode());
 
 		// invalid cc and bcc but valid to, mus count up the invalid accounts
 		recipients = new ArrayList<Identity>();
 		recipients.add(id1);
 		recipients.add(illegal3); // first
-		recipientsCC.add(illegal3); // second
-		result = MailerWithTemplate.getInstance().sendMailAsSeparateMails(null, recipients, recipientsCC, template, id6);
+		Identity recipientCC = illegal3; // second
+		result =sendMailAsSeparateMails(null, recipients, recipientCC, template, id6, null);
 		// mail will bounce back since address does not exist, but sent to local MTA
-		assertEquals(MailerResult.OK, result.getReturnCode());
+		assertEquals(MailerResult.RECIPIENT_ADDRESS_ERROR, result.getReturnCode());
 		assertEquals(2, result.getFailedIdentites().size());
 
 	}
+	
+	public MailerResult sendMailAsSeparateMails(MailContext mCtxt, List<Identity> recipientsTO,
+			Identity recipientCC, MailTemplate template, Identity sender, String metaId) {
+
+		MailerResult result = new MailerResult();
+		MailBundle[] bundles = mailManager.makeMailBundles(mCtxt, recipientsTO, template, sender, metaId, result);
+		result.append(mailManager.sendMessage(bundles));
+		
+		if(recipientCC != null) {
+			MailBundle ccBundle = mailManager.makeMailBundle(mCtxt, recipientCC, template, sender, metaId, result);
+			result.append(mailManager.sendMessage(ccBundle));
+		}
+
+		return result;
+	}
 }
\ No newline at end of file
diff --git a/src/test/java/org/olat/core/util/openxml/OpenXMLDocumentTest.java b/src/test/java/org/olat/core/util/openxml/OpenXMLDocumentTest.java
index 9d3c7e670823912b69f582a5c6f4c63d96d08313..1881be5a05c56f42111532f21b385751f492fb37 100644
--- a/src/test/java/org/olat/core/util/openxml/OpenXMLDocumentTest.java
+++ b/src/test/java/org/olat/core/util/openxml/OpenXMLDocumentTest.java
@@ -21,16 +21,10 @@ package org.olat.core.util.openxml;
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.net.URL;
 import java.util.zip.ZipOutputStream;
 
-import javax.xml.bind.Element;
-
 import org.apache.commons.io.IOUtils;
 import org.junit.Test;
-import org.olat.restapi.UserMgmtTest;
-
-import com.sun.xml.ws.policy.privateutil.PolicyUtils.Collections;
 
 /**
  * 
@@ -50,7 +44,6 @@ public class OpenXMLDocumentTest {
 		OpenXMLUtils.writeTo(document.getDocument(), System.out, true);
 	}
 
-	
 	@Test
 	public void writeDoc() throws Exception {
 		FileOutputStream fileOut = new FileOutputStream(new File("/HotCoffee/tmp/test_1_min.docx"));
@@ -68,10 +61,4 @@ public class OpenXMLDocumentTest {
 		IOUtils.closeQuietly(out);
 		IOUtils.closeQuietly(fileOut);
 	}
-	
-	
-	
-	
-	
-
 }