diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js
index 218922d5bc65e709999a692b114e23b2b5c8fc16..5b3e7eb4c4db7ffc53beac571610621cbaac1524 100644
--- a/javascript/src/iframe/viamapi-iframe.js
+++ b/javascript/src/iframe/viamapi-iframe.js
@@ -1410,6 +1410,9 @@ const connection = Penpal.connectToParent({
       return encodeResponse("200", "", "Document signed");
     },
     // passportUUID - String - passport to sign the vCard
+    // senderEmail - the email address of the sender
+    // attribs - additional attributes, to be added to the vCard. Recognized attribs are:
+    //   - emailService: "GMail", "Outlook 365", ...
     // text, html - String - the text and html part of the email, both optional
     // parts - array of objects, representing the MIME structure in format:
     // {
@@ -1421,7 +1424,7 @@ const connection = Penpal.connectToParent({
     //   body: String if it is a text part (Content-Type = "text/...") or Uint8Array otherwise; filled for leaf MIME nodes
     //   parts: array of instances of the same object; filled for container MIME nodes (Content-Type = "multipart/...")
     // }
-    signVCard: async (passportUUID, senderEmail, text, html, parts = null) => {
+    signVCard: async (passportUUID, senderEmail, attribs, textBody, htmlBody, parts) => {
       const authenticationPublicKey = localStorage.getItem(
         "authenticatedIdentity"
       );
@@ -1437,8 +1440,9 @@ const connection = Penpal.connectToParent({
       const messageUUID = makeid();
 
       const vCardAttribs = {
-        passportUUID: passportUUID,
-        messageUUID: messageUUID
+        ...attribs,
+        passportUUID,
+        messageUUID
       };
 
       let vCardImageData;
@@ -1501,31 +1505,47 @@ const connection = Penpal.connectToParent({
         );
       }
 
-      if (!parts) {
+      if (typeof parts === "undefined" || parts === null) {
         parts = [];
       }
 
-      if (html) {
+      if (htmlBody) {
+        if (typeof htmlBody !== "string") {
+          throw new Error("htmlBody is not string"); // should not happen
+        }
         const htmlPart = {
           headers: {
             "Content-Type": "text/html"
           },
-          body: html
+          body: htmlBody
         };
         parts.unshift(htmlPart);
+      } else {
+        console.log("Html body is not passed to signVCard, its value is ", {html: htmlBody});
       }
 
-      if (text) {
+      if (textBody) {
+        if (typeof textBody !== "string") {
+          throw new Error("textBody is not string"); // should not happen
+        }
         const textPart = {
           headers: {
             "Content-Type": "text/plain"
           },
-          body: text
+          body: textBody
         };
         parts.unshift(textPart);
+      } else {
+        console.log("Text body is not passed to signVCard, its value is ", {text: textBody});
       }
 
-      prepareVCardParts(parts);
+      const count = prepareVCardParts(parts);
+      if (count.textParts === 0) {
+        return encodeResponse("400", "", "No text parts passed to signVCard");
+      }
+      if (count.htmlParts === 0) {
+        return encodeResponse("400", "", "No html parts passed to signVCard");
+      }
 
       const certResponse = await getCertificateForPassport(passportUUID, true);
 
diff --git a/javascript/src/utilities/emailUtilities.js b/javascript/src/utilities/emailUtilities.js
index d9131fb2f095912e1ee65552d3bcaa756ea7b674..988f879940b4bd1cac8eb118367d6e8f7ff05413 100644
--- a/javascript/src/utilities/emailUtilities.js
+++ b/javascript/src/utilities/emailUtilities.js
@@ -136,11 +136,49 @@ export const extractHtmlBodyFromString = string => {
     .trim();
 };
 
-export const prepareVCardParts = parts => {
+const capitalizeHeaderName = str => {
+  if (!str || typeof str !== 'string') { return; }
+  const strChunks = splitBy(str,'-');
+  return  strChunks.map(capitalizeFirstLetter).join('-');
+};
+const splitBy = (string,separator) =>{
+  if (typeof string !== 'string') { return; }
+  return string.split(separator);
+};
+const capitalizeFirstLetter = (s) => {
+  if (typeof s !== 'string') { return; }
+  return s.charAt(0).toUpperCase() + s.slice(1);
+};
+
+export function prepareVCardParts(parts) {
   if (!parts) {
     return;
   }
+  const count = {
+    textParts: 0,
+    htmlParts: 0
+  };
   for (const part of parts) {
+    if (!part.headers) {
+      part.headers = {
+        "Content-Type": "application/octet-stream"
+      };
+    } else {
+      const capitalizedHeaders = {};
+      for (const key of Object.keys(part.headers)) {
+        capitalizedHeaders[capitalizeHeaderName(key)] = part.headers[key];
+      }
+      part.headers = capitalizedHeaders;
+      try {
+        if (part.headers["Content-Type"].startsWith("text/plain")) {
+          count.textParts++;
+        } else if (part.headers["Content-Type"].startsWith("text/html")) {
+          count.htmlParts++;
+        }
+      } catch (ignore) {
+        //ignore
+      }
+    }
     if (part.body) {
       if (typeof part.body === "string") {
         part.body = stringToUtf8Base64(part.body);
@@ -151,11 +189,14 @@ export const prepareVCardParts = parts => {
       if (part.body instanceof ArrayBuffer) {
         part.body = byteArrayToBase64(new Uint8Array(part.body));
       } else {
-        throw new Error('part body is neither string, nor Uint8Array, nor ArrayBuffer');
+        throw new Error('part body is neither string, nor Uint8Array, nor ArrayBuffer'); // should not happen
       }
     }
     if (part.parts) {
-      prepareVCardParts(part.parts);
+      const subcount = prepareVCardParts(part.parts);
+      count.textParts += subcount.textParts;
+      count.htmlParts += subcount.htmlParts;
     }
   }
-};
+  return count;
+}