diff --git a/entity/BulkMailAddRecipients_entity/entityfields/recipientcontactids/valueProcess.js b/entity/BulkMailAddRecipients_entity/entityfields/recipientcontactids/valueProcess.js
index 867801eb33a46e2945ad7759d7c48633e8217fc0..107d0af5ed33fdbed773fc5e8bbac0952a303646 100644
--- a/entity/BulkMailAddRecipients_entity/entityfields/recipientcontactids/valueProcess.js
+++ b/entity/BulkMailAddRecipients_entity/entityfields/recipientcontactids/valueProcess.js
@@ -1,21 +1,8 @@
-import("Contact_lib");
-import("system.result");
-import("Bulkmail_lib");
-import("KeywordRegistry_basic");
-import("system.util");
-import("system.db");
-import("Sql_lib");
-import("system.vars");
-
-var contactIds = JSON.parse(vars.getString("$param.ContactIds_param"));
-var bulkMailId = vars.get("$field.BULKMAIL_ID");
-
-var existsQuery = "not exists(select BULKMAILRECIPIENTID from BULKMAILRECIPIENT where BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID and # = ?)";
-var query = SqlCondition.begin()
-    .andIn("CONTACT.CONTACTID", contactIds)
-    .andPrepare("BULKMAILRECIPIENT.BULKMAIL_ID", bulkMailId, existsQuery) //only add contacts that aren't already recipients
-    .andSqlCondition(ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail(), true))  //check if there's a commrestriction
-    .buildSql("select CONTACTID from CONTACT");
-
-contactIds = db.array(db.COLUMN, query); 
-result.string(JSON.stringify(contactIds));
+import("system.result");
+import("Bulkmail_lib");
+import("system.vars");
+
+var contactIds = JSON.parse(vars.getString("$param.ContactIds_param"));
+var bulkMailId = vars.get("$field.BULKMAIL_ID");
+
+result.string(JSON.stringify(BulkMailUtils.filterNewRecipients(bulkMailId, contactIds)));
\ No newline at end of file
diff --git a/entity/BulkMail_entity/BulkMail_entity.aod b/entity/BulkMail_entity/BulkMail_entity.aod
index 5698ca8c63a18544148231bc0cbc783ff06401cc..eed32e047eeee11830af5758f92e36931aa249c1 100644
--- a/entity/BulkMail_entity/BulkMail_entity.aod
+++ b/entity/BulkMail_entity/BulkMail_entity.aod
@@ -1,210 +1,222 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.10" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.10">
-  <name>BulkMail_entity</name>
-  <majorModelMode>DISTRIBUTED</majorModelMode>
-  <icon>VAADIN:AT</icon>
-  <title>Bulk mail</title>
-  <contentTitleProcess>%aditoprj%/entity/BulkMail_entity/contentTitleProcess.js</contentTitleProcess>
-  <titlePlural>Bulk mails</titlePlural>
-  <recordContainer>db</recordContainer>
-  <entityFields>
-    <entityProvider>
-      <name>#PROVIDER</name>
-      <dependencies>
-        <entityDependency>
-          <name>88f8ded7-fe8f-41ef-8e01-030bae0867ee</name>
-          <entityName>BulkMailAddRecipients_entity</entityName>
-          <fieldName>BulkMails</fieldName>
-          <isConsumer v="false" />
-        </entityDependency>
-      </dependencies>
-    </entityProvider>
-    <entityField>
-      <name>BULKMAILID</name>
-    </entityField>
-    <entityField>
-      <name>NAME</name>
-      <title>Name</title>
-      <mandatory v="true" />
-    </entityField>
-    <entityField>
-      <name>SUBJECT</name>
-      <title>Subject</title>
-    </entityField>
-    <entityField>
-      <name>DESCRIPTION</name>
-      <title>Description</title>
-    </entityField>
-    <entityField>
-      <name>DOCUMENTTEMPLATE_ID</name>
-      <title>Document Template</title>
-      <consumer>Templates</consumer>
-      <mandatory v="false" />
-      <onValueChange>%aditoprj%/entity/BulkMail_entity/entityfields/documenttemplate_id/onValueChange.js</onValueChange>
-    </entityField>
-    <entityConsumer>
-      <name>Recipients</name>
-      <dependency>
-        <name>dependency</name>
-        <entityName>BulkMailRecipient_entity</entityName>
-        <fieldName>BulkMailRecipients</fieldName>
-      </dependency>
-      <children>
-        <entityParameter>
-          <name>BulkMailId_param</name>
-          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/recipients/children/bulkmailid_param/valueProcess.js</valueProcess>
-        </entityParameter>
-      </children>
-    </entityConsumer>
-    <entityConsumer>
-      <name>Templates</name>
-      <dependency>
-        <name>dependency</name>
-        <entityName>DocumentTemplate_entity</entityName>
-        <fieldName>DocumentTemplateProvider</fieldName>
-      </dependency>
-      <children>
-        <entityParameter>
-          <name>DocumentTemplateType_param</name>
-          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/templates/children/documenttemplatetype_param/valueProcess.js</valueProcess>
-        </entityParameter>
-        <entityParameter>
-          <name>DocumentTemplateTypeClassification_param</name>
-          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/templates/children/documenttemplatetypeclassification_param/valueProcess.js</valueProcess>
-        </entityParameter>
-      </children>
-    </entityConsumer>
-    <entityField>
-      <name>STATUS</name>
-      <title>Status</title>
-      <consumer>StatusKeyword</consumer>
-      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/status/valueProcess.js</valueProcess>
-      <displayValueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/status/displayValueProcess.js</displayValueProcess>
-    </entityField>
-    <entityField>
-      <name>SENDER</name>
-      <title>Sender address</title>
-      <mandatory v="true" />
-      <onValidation>%aditoprj%/entity/BulkMail_entity/entityfields/sender/onValidation.js</onValidation>
-    </entityField>
-    <entityActionField>
-      <name>sendMail</name>
-      <title>Send</title>
-      <onActionProcess>%aditoprj%/entity/BulkMail_entity/entityfields/sendmail/onActionProcess.js</onActionProcess>
-      <iconId>VAADIN:PAPERPLANE</iconId>
-      <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/sendmail/stateProcess.js</stateProcess>
-    </entityActionField>
-    <entityField>
-      <name>ICON</name>
-      <contentType>IMAGE</contentType>
-      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/icon/valueProcess.js</valueProcess>
-    </entityField>
-    <entityField>
-      <name>preview</name>
-      <contentType>HTML</contentType>
-      <displayValueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/preview/displayValueProcess.js</displayValueProcess>
-    </entityField>
-    <entityConsumer>
-      <name>StatusKeyword</name>
-      <dependency>
-        <name>dependency</name>
-        <entityName>KeywordEntry_entity</entityName>
-        <fieldName>SpecificContainerKeywords</fieldName>
-      </dependency>
-      <children>
-        <entityParameter>
-          <name>ContainerName_param</name>
-          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/statuskeyword/children/containername_param/valueProcess.js</valueProcess>
-        </entityParameter>
-      </children>
-    </entityConsumer>
-    <entityField>
-      <name>BINDATA</name>
-      <contentType>FILE</contentType>
-      <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/bindata/stateProcess.js</stateProcess>
-    </entityField>
-    <entityFieldGroup>
-      <name>subjectPreview</name>
-      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/subjectpreview/valueProcess.js</valueProcess>
-      <fields>
-        <element>SUBJECT</element>
-      </fields>
-    </entityFieldGroup>
-    <entityActionField>
-      <name>openAdminView</name>
-      <title>Open admin view</title>
-      <onActionProcess>%aditoprj%/entity/BulkMail_entity/entityfields/openadminview/onActionProcess.js</onActionProcess>
-      <iconId>VAADIN:CURLY_BRACKETS</iconId>
-      <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/openadminview/stateProcess.js</stateProcess>
-    </entityActionField>
-  </entityFields>
-  <recordContainers>
-    <dbRecordContainer>
-      <name>db</name>
-      <alias>Data_alias</alias>
-      <fromClauseProcess>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/fromClauseProcess.js</fromClauseProcess>
-      <onDBInsert>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/onDBInsert.js</onDBInsert>
-      <onDBUpdate>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/onDBUpdate.js</onDBUpdate>
-      <onDBDelete>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/onDBDelete.js</onDBDelete>
-      <linkInformation>
-        <linkInformation>
-          <name>6444866d-42ee-4b7b-8536-6dc8f6437c45</name>
-          <tableName>BULKMAIL</tableName>
-          <primaryKey>BULKMAILID</primaryKey>
-          <isUIDTable v="true" />
-          <readonly v="false" />
-        </linkInformation>
-        <linkInformation>
-          <name>914d6373-4409-44e5-882a-3f795b196d7b</name>
-          <tableName>DOCUMENTTEMPLATE</tableName>
-          <primaryKey>DOCUMENTTEMPLATEID</primaryKey>
-          <isUIDTable v="false" />
-          <readonly v="true" />
-        </linkInformation>
-      </linkInformation>
-      <recordFieldMappings>
-        <dbRecordFieldMapping>
-          <name>BULKMAILID.value</name>
-          <recordfield>BULKMAIL.BULKMAILID</recordfield>
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>DESCRIPTION.value</name>
-          <recordfield>BULKMAIL.DESCRIPTION</recordfield>
-          <isFilterable v="true" />
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>DOCUMENTTEMPLATE_ID.value</name>
-          <recordfield>BULKMAIL.DOCUMENTTEMPLATE_ID</recordfield>
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>NAME.value</name>
-          <recordfield>BULKMAIL.NAME</recordfield>
-          <isFilterable v="true" />
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>SUBJECT.value</name>
-          <recordfield>BULKMAIL.SUBJECT</recordfield>
-          <isFilterable v="true" />
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>SENDER.value</name>
-          <recordfield>BULKMAIL.SENDER</recordfield>
-          <isFilterable v="true" />
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>DOCUMENTTEMPLATE_ID.displayValue</name>
-          <recordfield>DOCUMENTTEMPLATE.NAME</recordfield>
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>STATUS.value</name>
-          <recordfield>BULKMAIL.STATUS</recordfield>
-          <isFilterable v="true" />
-        </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>STATUS.displayValue</name>
-          <expression>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/recordfieldmappings/status.displayvalue/expression.js</expression>
-        </dbRecordFieldMapping>
-      </recordFieldMappings>
-    </dbRecordContainer>
-  </recordContainers>
-</entity>
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.10" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.10">
+  <name>BulkMail_entity</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <icon>VAADIN:AT</icon>
+  <title>Bulk mail</title>
+  <contentTitleProcess>%aditoprj%/entity/BulkMail_entity/contentTitleProcess.js</contentTitleProcess>
+  <titlePlural>Bulk mails</titlePlural>
+  <recordContainer>db</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+      <dependencies>
+        <entityDependency>
+          <name>88f8ded7-fe8f-41ef-8e01-030bae0867ee</name>
+          <entityName>BulkMailAddRecipients_entity</entityName>
+          <fieldName>BulkMails</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+    </entityProvider>
+    <entityField>
+      <name>BULKMAILID</name>
+    </entityField>
+    <entityField>
+      <name>NAME</name>
+      <title>Name</title>
+      <mandatory v="true" />
+    </entityField>
+    <entityField>
+      <name>SUBJECT</name>
+      <title>Subject</title>
+    </entityField>
+    <entityField>
+      <name>DESCRIPTION</name>
+      <title>Description</title>
+    </entityField>
+    <entityField>
+      <name>DOCUMENTTEMPLATE_ID</name>
+      <title>Document Template</title>
+      <consumer>Templates</consumer>
+      <mandatory v="false" />
+      <onValueChange>%aditoprj%/entity/BulkMail_entity/entityfields/documenttemplate_id/onValueChange.js</onValueChange>
+    </entityField>
+    <entityConsumer>
+      <name>Recipients</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>BulkMailRecipient_entity</entityName>
+        <fieldName>BulkMailRecipients</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>BulkMailId_param</name>
+          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/recipients/children/bulkmailid_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityConsumer>
+      <name>Templates</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>DocumentTemplate_entity</entityName>
+        <fieldName>DocumentTemplateProvider</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>DocumentTemplateType_param</name>
+          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/templates/children/documenttemplatetype_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>DocumentTemplateTypeClassification_param</name>
+          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/templates/children/documenttemplatetypeclassification_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityField>
+      <name>STATUS</name>
+      <title>Status</title>
+      <consumer>StatusKeyword</consumer>
+      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/status/valueProcess.js</valueProcess>
+      <displayValueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/status/displayValueProcess.js</displayValueProcess>
+    </entityField>
+    <entityField>
+      <name>SENDER</name>
+      <title>Sender address</title>
+      <mandatory v="true" />
+      <onValidation>%aditoprj%/entity/BulkMail_entity/entityfields/sender/onValidation.js</onValidation>
+    </entityField>
+    <entityActionField>
+      <name>sendMail</name>
+      <title>Send</title>
+      <onActionProcess>%aditoprj%/entity/BulkMail_entity/entityfields/sendmail/onActionProcess.js</onActionProcess>
+      <iconId>VAADIN:PAPERPLANE</iconId>
+      <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/sendmail/stateProcess.js</stateProcess>
+    </entityActionField>
+    <entityField>
+      <name>ICON</name>
+      <contentType>IMAGE</contentType>
+      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/icon/valueProcess.js</valueProcess>
+    </entityField>
+    <entityField>
+      <name>preview</name>
+      <contentType>HTML</contentType>
+      <displayValueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/preview/displayValueProcess.js</displayValueProcess>
+    </entityField>
+    <entityConsumer>
+      <name>StatusKeyword</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>KeywordEntry_entity</entityName>
+        <fieldName>SpecificContainerKeywords</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>ContainerName_param</name>
+          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/statuskeyword/children/containername_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityField>
+      <name>BINDATA</name>
+      <contentType>FILE</contentType>
+      <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/bindata/stateProcess.js</stateProcess>
+    </entityField>
+    <entityFieldGroup>
+      <name>subjectPreview</name>
+      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/subjectpreview/valueProcess.js</valueProcess>
+      <fields>
+        <element>SUBJECT</element>
+      </fields>
+    </entityFieldGroup>
+    <entityActionField>
+      <name>openAdminView</name>
+      <title>Open admin view</title>
+      <onActionProcess>%aditoprj%/entity/BulkMail_entity/entityfields/openadminview/onActionProcess.js</onActionProcess>
+      <iconId>VAADIN:CURLY_BRACKETS</iconId>
+      <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/openadminview/stateProcess.js</stateProcess>
+    </entityActionField>
+    <entityParameter>
+      <name>PresetRecipients_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityField>
+      <name>content</name>
+      <title>Content</title>
+      <contentType>HTML</contentType>
+      <contentTypeProcess>%aditoprj%/entity/BulkMail_entity/entityfields/content/contentTypeProcess.js</contentTypeProcess>
+      <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/content/stateProcess.js</stateProcess>
+      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/content/valueProcess.js</valueProcess>
+    </entityField>
+  </entityFields>
+  <recordContainers>
+    <dbRecordContainer>
+      <name>db</name>
+      <alias>Data_alias</alias>
+      <fromClauseProcess>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/fromClauseProcess.js</fromClauseProcess>
+      <onDBInsert>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/onDBInsert.js</onDBInsert>
+      <onDBUpdate>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/onDBUpdate.js</onDBUpdate>
+      <onDBDelete>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/onDBDelete.js</onDBDelete>
+      <linkInformation>
+        <linkInformation>
+          <name>6444866d-42ee-4b7b-8536-6dc8f6437c45</name>
+          <tableName>BULKMAIL</tableName>
+          <primaryKey>BULKMAILID</primaryKey>
+          <isUIDTable v="true" />
+          <readonly v="false" />
+        </linkInformation>
+        <linkInformation>
+          <name>914d6373-4409-44e5-882a-3f795b196d7b</name>
+          <tableName>DOCUMENTTEMPLATE</tableName>
+          <primaryKey>DOCUMENTTEMPLATEID</primaryKey>
+          <isUIDTable v="false" />
+          <readonly v="true" />
+        </linkInformation>
+      </linkInformation>
+      <recordFieldMappings>
+        <dbRecordFieldMapping>
+          <name>BULKMAILID.value</name>
+          <recordfield>BULKMAIL.BULKMAILID</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>DESCRIPTION.value</name>
+          <recordfield>BULKMAIL.DESCRIPTION</recordfield>
+          <isFilterable v="true" />
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>DOCUMENTTEMPLATE_ID.value</name>
+          <recordfield>BULKMAIL.DOCUMENTTEMPLATE_ID</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>NAME.value</name>
+          <recordfield>BULKMAIL.NAME</recordfield>
+          <isFilterable v="true" />
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>SUBJECT.value</name>
+          <recordfield>BULKMAIL.SUBJECT</recordfield>
+          <isFilterable v="true" />
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>SENDER.value</name>
+          <recordfield>BULKMAIL.SENDER</recordfield>
+          <isFilterable v="true" />
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>DOCUMENTTEMPLATE_ID.displayValue</name>
+          <recordfield>DOCUMENTTEMPLATE.NAME</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>STATUS.value</name>
+          <recordfield>BULKMAIL.STATUS</recordfield>
+          <isFilterable v="true" />
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>STATUS.displayValue</name>
+          <expression>%aditoprj%/entity/BulkMail_entity/recordcontainers/db/recordfieldmappings/status.displayvalue/expression.js</expression>
+        </dbRecordFieldMapping>
+      </recordFieldMappings>
+    </dbRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/BulkMail_entity/entityfields/content/contentTypeProcess.js b/entity/BulkMail_entity/entityfields/content/contentTypeProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7996a89667933fc400f3fe807ef1a03e8b71f57
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/content/contentTypeProcess.js
@@ -0,0 +1,15 @@
+import("system.result");
+import("Document_lib");
+import("system.vars");
+
+var upload = vars.get("$field.BINDATA");
+var filename = DocumentUtil.getFilenameFromUpload(upload);
+var type = DocumentUtil.getFileExtensionFromUpload(filename);
+result.string(
+    ({
+        "txt" : "LONG_TEXT",
+        "html" : "HTML",
+        "htm" : "HTML",
+        "eml" : "HTML"
+    })[type] || "LONG_TEXT"
+);
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/content/stateProcess.js b/entity/BulkMail_entity/entityfields/content/stateProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..3556de9c2f8a50d3a7d0eaee2900e769c1eb2a9c
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/content/stateProcess.js
@@ -0,0 +1,8 @@
+import("system.result");
+import("system.neon");
+import("system.vars");
+
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
+    result.string(neon.COMPONENTSTATE_EDITABLE);
+else
+    result.string(neon.COMPONENTSTATE_INVISIBLE);
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/content/valueProcess.js b/entity/BulkMail_entity/entityfields/content/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b157c6cc8c6ee66d4083c68bee963b411b2748e
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/content/valueProcess.js
@@ -0,0 +1,24 @@
+import("Document_lib");
+import("system.util");
+import("system.result");
+import("system.vars");
+import("system.db");
+import("DocumentTemplate_lib");
+
+if (vars.get("$this.value") == null)
+{
+    var upload = vars.get("$field.BINDATA");
+    var binData = DocumentUtil.getBindataFromUpload(upload);
+    var filename = DocumentUtil.getFilenameFromUpload(upload);
+    var type = DocumentUtil.getFileExtensionFromUpload(filename);
+    type = ({
+        "txt" : DocumentTemplate.types.TXT,
+        "html" : DocumentTemplate.types.HTML,
+        "htm" : DocumentTemplate.types.HTML,
+        "eml" : DocumentTemplate.types.EML
+    })[type];
+    var template = new DocumentTemplate(binData, type);
+    var content = template.getReplacedContent({}, true);
+
+    result.string(content);
+}
diff --git a/entity/BulkMail_entity/recordcontainers/db/onDBInsert.js b/entity/BulkMail_entity/recordcontainers/db/onDBInsert.js
index 92c78050f4f47399cbc67955957249934a206692..1a0d7b3b5e8ed56dc8088006903a9851f1bbef62 100644
--- a/entity/BulkMail_entity/recordcontainers/db/onDBInsert.js
+++ b/entity/BulkMail_entity/recordcontainers/db/onDBInsert.js
@@ -1,23 +1,35 @@
-import("system.result");
-import("system.vars");
-import("system.db");
-import("system.util");
-import("Document_lib");
-
-//TODO - Function
-
-var bindataUpload = DocumentUtil.getBindataFromUpload(vars.get("$field.BINDATA"));
-var filename = "";
-var bindata = "";
-
-if(bindataUpload != "")
-{
-    filename = DocumentUtil.getFilenameFromUpload(vars.get("$field.BINDATA"));
-    bindata  = bindataUpload;
-}
-
-if(bindata != "" && filename != "")
-{
-    db.insertBinary("BULKMAIL", "DOCUMENT", vars.get("$field.BULKMAILID"), 
-                    "", bindata, filename, "", "", "_____SYSTEMALIAS");
-}
\ No newline at end of file
+import("system.result");
+import("system.vars");
+import("system.db");
+import("system.util");
+import("Document_lib");
+import("Bulkmail_lib");
+
+//TODO - Function
+
+var content = vars.get("$field.content");
+var originalBinData = vars.get("$field.BINDATA");
+var filename;
+
+if(vars.get("$field.BINDATA"))
+    filename = DocumentUtil.getFilenameFromUpload(vars.get("$field.BINDATA"));
+
+var type = DocumentUtil.getFileExtensionFromUpload(filename);
+if (type == "html" || type == "eml")
+    content = "<html>" + content + "</html>";
+
+var bindata = util.encodeBase64String(content);
+if (!filename)
+    filename = vars.get("$field.NAME") + ".txt";
+
+if(bindata != "")
+{
+    db.insertBinary("BULKMAIL", "DOCUMENT", vars.get("$field.BULKMAILID"), 
+                    "", bindata, filename, "", "", "_____SYSTEMALIAS");
+}
+
+var contactIds = JSON.parse(vars.getString("$param.PresetRecipients_param"));
+var bulkMailId = vars.get("$field.BULKMAILID");
+
+if (contactIds && contactIds.length > 0)
+    BulkMailUtils.addRecipients(bulkMailId, BulkMailUtils.filterNewRecipients(bulkMailId, contactIds));
\ No newline at end of file
diff --git a/entity/CampaignStep_entity/CampaignStep_entity.aod b/entity/CampaignStep_entity/CampaignStep_entity.aod
index b206a72faa468d08c591e1de37737a5acca10437..92d59a1b933c236b6a986171d830aa136e2da2bb 100644
--- a/entity/CampaignStep_entity/CampaignStep_entity.aod
+++ b/entity/CampaignStep_entity/CampaignStep_entity.aod
@@ -368,6 +368,12 @@
       <consumer>CampaignStepMedium</consumer>
       <displayValueProcess>%aditoprj%/entity/CampaignStep_entity/entityfields/stepmedium/displayValueProcess.js</displayValueProcess>
     </entityField>
+    <entityActionField>
+      <name>newBulkMail</name>
+      <title>Write bulk mail</title>
+      <onActionProcess>%aditoprj%/entity/CampaignStep_entity/entityfields/newbulkmail/onActionProcess.js</onActionProcess>
+      <iconId>VAADIN:AT</iconId>
+    </entityActionField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
diff --git a/entity/CampaignStep_entity/entityfields/newbulkmail/onActionProcess.js b/entity/CampaignStep_entity/entityfields/newbulkmail/onActionProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..f1ed0b790f38d89d6b30d2eb7de8c8efa3d42a02
--- /dev/null
+++ b/entity/CampaignStep_entity/entityfields/newbulkmail/onActionProcess.js
@@ -0,0 +1,10 @@
+import("Sql_lib");
+import("system.db");
+import("Bulkmail_lib");
+
+var recipients = db.array(db.COLUMN, SqlCondition.begin()
+    .andPrepareVars("CAMPAIGNPARTICIPANT.CAMPAIGNSTEP_ID", "$field.CAMPAIGNSTEPID")
+    .andPrepareVars("CAMPAIGNPARTICIPANT.CAMPAIGN_ID", "$field.CAMPAIGN_ID")
+    .buildSql("select CONTACT_ID from CAMPAIGNPARTICIPANT"));
+
+BulkMailUtils.newBulkMail(recipients);
\ No newline at end of file
diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
index 5883345c2a754356871ede075ede9f24a8183e9b..11ccd000ad0997ff5e1fbdacb9e983c3ba551de7 100644
--- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
+++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
@@ -41,6 +41,10 @@
       <key>The following data has been anonymised: %0</key>
       <value>Die folgenden Daten wurden anonymisiert: %0</value>
     </entry>
+    <entry>
+      <key>Write bulk mail</key>
+      <value>Serienmail schreiben</value>
+    </entry>
     <entry>
       <key>MAX</key>
       <value>maximal</value>
diff --git a/neonView/BulkMailEdit_view/BulkMailEdit_view.aod b/neonView/BulkMailEdit_view/BulkMailEdit_view.aod
index 0f2c9009d08069b40cd8082687e39250ec8c88bc..6f3346a08a1be5d5ebcb37146c2554d55f385a3c 100644
--- a/neonView/BulkMailEdit_view/BulkMailEdit_view.aod
+++ b/neonView/BulkMailEdit_view/BulkMailEdit_view.aod
@@ -37,6 +37,10 @@
           <name>e4ec09c2-3815-4a3b-bce8-c12d5b919b04</name>
           <entityField>SENDER</entityField>
         </entityFieldLink>
+        <entityFieldLink>
+          <name>0a67f430-dbcd-4605-b626-ee6d715ab248</name>
+          <entityField>content</entityField>
+        </entityFieldLink>
       </fields>
     </genericViewTemplate>
   </children>
diff --git a/process/Bulkmail_lib/process.js b/process/Bulkmail_lib/process.js
index 6d109c2b4464ca97ae2e2e22fe0a621a4a8129c9..f262b0fc0ca14ccf163379f82aeb043945bbb8af 100644
--- a/process/Bulkmail_lib/process.js
+++ b/process/Bulkmail_lib/process.js
@@ -193,6 +193,26 @@ BulkMailUtils.isRecipient = function (pBulkMailId, pContactId)
     ) != "0";
 }
 
+BulkMailUtils.newBulkMail = function (pRecipients)
+{
+    var params = {
+        "PresetRecipients_param" : JSON.stringify(pRecipients)
+    };
+    neon.openContext("BulkMail", "BulkMailEdit_view", null, neon.OPERATINGSTATE_NEW, params);
+}
+
+BulkMailUtils.filterNewRecipients = function (pBulkMailId, pContactIds)
+{
+    var existsQuery = "not exists(select BULKMAILRECIPIENTID from BULKMAILRECIPIENT where BULKMAILRECIPIENT.CONTACT_ID = CONTACT.CONTACTID and # = ?)";
+    var query = SqlCondition.begin()
+        .andIn("CONTACT.CONTACTID", pContactIds)
+        .andPrepare("BULKMAILRECIPIENT.BULKMAIL_ID", pBulkMailId, existsQuery) //only add contacts that aren't already recipients
+        .andSqlCondition(ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail(), true))  //check if there's a commrestriction
+        .buildSql("select CONTACTID from CONTACT");
+
+    return db.array(db.COLUMN, query); 
+}
+
 function SerialLetterUtils () {}
 
 /**
diff --git a/process/DocumentTemplate_lib/process.js b/process/DocumentTemplate_lib/process.js
index 88552ead95189013c86b300d169d9eb9abfe536a..dbcfb36a91297076174750b3f86105e75e375448 100644
--- a/process/DocumentTemplate_lib/process.js
+++ b/process/DocumentTemplate_lib/process.js
@@ -126,10 +126,11 @@ DocumentTemplate.prototype._getRequiredPlaceholders = function ()
  * replace function for the type.
  * 
  * @param {Object} pReplacements map, the structure is {placeholder : value}
+ * @param {boolean} pDecoded if the replaced content should be not base64 encoded
  * 
  * @return {String} the replaced content
  */
-DocumentTemplate.prototype.getReplacedContent = function (pReplacements)
+DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pDecoded)
 {
     switch (this.type)
     {
@@ -137,8 +138,11 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements)
             for (let i in pReplacements)
                 pReplacements[i] = text.text2html(pReplacements[i], false);
         case DocumentTemplate.types.TXT:
-            let decodedContent = util.decodeBase64String(this.content)
-            return util.encodeBase64String(DocumentTemplate._replaceText(decodedContent, pReplacements));
+            let decodedContent = util.decodeBase64String(this.content);
+            let encodedContent = DocumentTemplate._replaceText(decodedContent, pReplacements);
+            if (!pDecoded)
+                encodedContent = util.encodeBase64String(encodedContent);
+            return encodedContent;
         case DocumentTemplate.types.EML:
             return this._getReplacedEML(pReplacements);
         case DocumentTemplate.types.ODT:
@@ -247,7 +251,7 @@ DocumentTemplate.prototype.getReplacedEmailsByContactIds = function (pContactIds
         }
         else
         {
-            let body = this.getReplacedContent(replacements[contactId]);
+            let body = this.getReplacedContent(replacements[contactId], true);
             if (this.type == DocumentTemplate.types.TXT || this.type == DocumentTemplate.types.PLAIN)
                 body = text.text2html(body, false);
             emailObj[contactId] = new Email(null, null, null, body);