import("Document_lib"); import("system.logging"); import("system.translate"); import("system.text"); import("system.db"); import("system.util"); import("Communication_lib"); import("DocumentTemplate_lib"); import("system.neon"); import("system.mail"); import("Bulkmail_lib") function EmailWritingUtils () {} /** * creates a new E-Mail-Object and ask for a download of a eml where all fields are prefilled * The eml can be open with a mailclient and sent via the mailclient. Each mailclient has a different behaviour: * In Outlook the mail is automatically opened in draft-mode * In Thunderbird the mail is opened in view mode and you've to manually "edit as new" * * @param {String|Array} pToRecipients mailaddresses of the recipients, can either be a 1D-Array with several addresses or a string with one address * @param {String} pSenderContactId contactId of the sender. the standard mailadress of the contact is used as sender-address * @param {String} [pTemplateId] if a document-template shall be used, give the templateId here * @param {String} [pRecipientContactId] contactId of the recipient, required to fill placeholders * @param {String} [pBindata] base64 binary data * @return {Array} the eml document as array with [filename, base64] */ EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId, pTemplateId, pRecipientContactId, pBindata) { if (pToRecipients && typeof(pToRecipients) == "string") pToRecipients = [pToRecipients]; var email; if (pTemplateId || pBindata) email = Email.fromTemplate(pTemplateId, pRecipientContactId, pBindata) else email = new Email(); email.setSender(pSenderContactId); if (pToRecipients) email.toRecipients = pToRecipients; email.bccRecipients = [EmailWritingUtils.getMailbridgeAddress()]; return email.downloadEML(); } /** * opens a view where a new mail can be sent. In the view the use CAN select a DocumentTemplate if needed * * @param {String} pToContactId contactId with contacts to filter the communication-addresses * @param {String} [pToEmailAddress] email address as string that shall be used as recipient-preset */ EmailWritingUtils.openNewMail = function (pToContactId, pToEmailAddress) { var params = { "ContactId_param" : pToContactId }; if (pToEmailAddress) params.Recipient_param = pToEmailAddress; neon.openContext("Email", "EmailEdit_view", null, neon.OPERATINGSTATE_NEW, params); } EmailWritingUtils.getMailbridgeAddress = function () { return "mailbridge@domain.local"; //TODO: not hardcoded } /** * object for handling emails * @param {String} [pBody=null] if given, the body is set to this text * @class */ function Email(pBody) { if (pBody == undefined) pBody = null; this.sender = null; this.subject = null; this.body = pBody; this.toRecipients = []; this.ccRecipients = []; this.bccRecipients = []; this.emlFile = null; } /** * makes an Email object from a RFC * NOTE: body is not editable if comming from a eml. Use it only for preview! * * @param {String} pBase64RFC the RFC mail, base64 encoded * @return {Email} a new Email object */ Email.fromRFC = function (pBase64RFC) { var decoded = util.decodeBase64String(pBase64RFC); var mailData = mail.parseRFC(decoded); var newMail = new Email(mailData[mail.MAIL_HTMLTEXT]); newMail.subject = mailData[mail.MAIL_SUBJECT]; newMail.emlFile = decoded; return newMail; } Email.fromTemplate = function (pTemplateId, pContactId, pBindata) { var template; if (pBindata && pBindata.isFilled()) { if (BulkMailUtils.isValidMimeType(pBindata.mimeType)) { template = new DocumentTemplate(pBindata.bindata, DocumentTemplate.types.fromMimeType(pBindata.mimeType), pBindata.filename, true); } } else template = DocumentTemplate.loadTemplate(pTemplateId); return Email.getReplacedBulkEmails(template, [pContactId])[pContactId]; } /** * Replaces the placeholders with data from the contacts and returns the resulting Emails. * @param {DocumentTemplate} pTemplate a document template which is used for all mails * @param {Array} pContactIds Contact ids of all recipients * * @return {Object} Object containing the contact ids as keys and the corresponding Email * objects as values */ Email.getReplacedBulkEmails = function(pTemplate, pContactIds) { var emailObjects = {}; var isEML = pTemplate.type == DocumentTemplate.types.EML; var emailContents = pTemplate.getReplacedContentByContactIds(pContactIds, isEML); for (contactId in emailContents) { if (isEML) { emailObjects[contactId] = Email.fromRFC(emailContents[contactId]); } else { // convert to HTML if needed if (pTemplate.type == DocumentTemplate.types.TXT || pTemplate.type == DocumentTemplate.types.PLAIN) emailContents[contactId] = text.text2html(emailContents[contactId], false); emailObjects[contactId] = new Email(emailContents[contactId]); } } return emailObjects; } /** * sets the sender of the mail * * @param {String} pContactId the contactId of the sender */ Email.prototype.setSender = function (pContactId) { this.sender = CommUtil.getStandardMail(pContactId); } /** * generates a 'mailto:' URL from the email object */ Email.prototype.getMailtoUrl = function () { var url = []; if (this.toRecipients.length) url.push("to=" + this.toRecipients.join()); if (this.ccRecipients.length) url.push("cc=" + this.ccRecipients.join()); if (this.bccRecipients.length) url.push("bcc=" + this.bccRecipients.join()); if (this.subject) url.push("subject=" + this.subject); if (this.body) url.push("body=" + text.html2text(this.body)); url = "mailto:?" + url.join("&"); return encodeURI(url); } Email.prototype._newMailObject = function() { var ENCODING = "UTF-8"; var mailId; var emlFile = this.emlFile ? this.emlFile : null; try { if (emlFile) mailId = mail.newMail(emlFile, mail.FORMAT_MIME); else mailId = mail.newMail(); } catch(ex) { //TODO: fix this dirty workaround [waiting for #1038963], since newMail causes an error on the first call after a user logged in logging.log(ex); util.sleep(1500); if (emlFile) mailId = mail.newMail(emlFile, mail.FORMAT_MIME); else mailId = mail.newMail(); } if (emlFile) { mail.clearRecipients(mailId, mail.RECIPIENT_TO); mail.clearRecipients(mailId, mail.RECIPIENT_CC); mail.clearRecipients(mailId, mail.RECIPIENT_BCC); } if (this.toRecipients.length) mail.addRecipients(mailId, mail.RECIPIENT_TO, this.toRecipients); if (this.ccRecipients.length) mail.addRecipients(mailId, mail.RECIPIENT_CC, this.ccRecipients); if (this.bccRecipients.length) mail.addRecipients(mailId, mail.RECIPIENT_BCC, this.bccRecipients); mail.setSubject(mailId, this.subject || "", ENCODING); // only alter subject and text, if no eml is used if (!emlFile) { if (this.body) mail.addText(mailId, this.body, "text/html", ENCODING, null); else mail.addText(mailId, "", "text/html", ENCODING, null); } return mailId; } /** * generates a eml-element from the email object */ Email.prototype.getRFCmail = function () { var ENCODING = "UTF-8"; var mailId = this._newMailObject() //"X-Unsent" is a very badly, non-standardised header to gently ask the mail client that the mail should open in a compose-mode //this is mainly done for Microsoft Outlook for Windows. //Thunderbird has a dinosaur-request (it's from the year 2002) to also support this: https://bugzilla.mozilla.org/show_bug.cgi?id=166541 mail.addHeader(mailId, "X-Unsent", "1"); //accoding to this entry: https://stackoverflow.com/questions/11330628/os-x-mail-open-eml-files-in-compose-mode/33224913 //something similar exists for OS X Mail //X-Uniform-Type-Identifier: com.apple.mail-draft //this could be added later if needed var mailObj = mail.getCachedMail(mailId); var finalMail = mail.toRFC(mailObj); // remove from cache mail.deleteMail(mailId) return finalMail; } /** * opens the email */ Email.prototype.openMail = function () { neon.openUrl(this.getMailtoUrl(), false); } /** * ask for a download of the email * * @return {Array} array of [filename, EML (base64)] */ Email.prototype.downloadEML = function () { var eml = this.getEML(); var filename = (this.subject || translate.text("Email Template")) + ".eml"; neon.download(eml, filename); return [filename, eml]; } /** * @return {String} RFC mail (base64 encoded) */ Email.prototype.getEML = function () { return util.encodeBase64String(this.getRFCmail(), null); } /** * sends the email object * * @return {boolean} true, if the mail was sent sucessfully */ Email.prototype.send = function (pUser) { try { mailId = this._newMailObject(); if (this.sender) mail.setSender(mailId, this.sender); var sentMails = mail.sendMailAs(pUser || "mailbridge", mailId) // remove from cache mail.deleteMail(mailId) return sentMails > 0; } catch (ex) { logging.log(ex); return false; } }