diff options
Diffstat (limited to 'comm/mailnews/compose/test/unit/test_messageHeaders.js')
-rw-r--r-- | comm/mailnews/compose/test/unit/test_messageHeaders.js | 812 |
1 files changed, 812 insertions, 0 deletions
diff --git a/comm/mailnews/compose/test/unit/test_messageHeaders.js b/comm/mailnews/compose/test/unit/test_messageHeaders.js new file mode 100644 index 0000000000..58765e219f --- /dev/null +++ b/comm/mailnews/compose/test/unit/test_messageHeaders.js @@ -0,0 +1,812 @@ +/* + * Test suite for ensuring that the headers of messages are set properly. + */ + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +const { MimeParser } = ChromeUtils.import("resource:///modules/mimeParser.jsm"); + +var CompFields = CC( + "@mozilla.org/messengercompose/composefields;1", + Ci.nsIMsgCompFields +); + +function makeAttachment(opts = {}) { + let attachment = Cc[ + "@mozilla.org/messengercompose/attachment;1" + ].createInstance(Ci.nsIMsgAttachment); + for (let key in opts) { + attachment[key] = opts[key]; + } + return attachment; +} + +function sendMessage(fieldParams, identity, opts = {}, attachments = []) { + // Initialize compose fields + let fields = new CompFields(); + for (let key in fieldParams) { + fields[key] = fieldParams[key]; + } + for (let attachment of attachments) { + fields.addAttachment(attachment); + } + + // Initialize compose params + let params = Cc[ + "@mozilla.org/messengercompose/composeparams;1" + ].createInstance(Ci.nsIMsgComposeParams); + params.composeFields = fields; + for (let key in opts) { + params[key] = opts[key]; + } + + // Send the message + let msgCompose = MailServices.compose.initCompose(params); + let progress = Cc["@mozilla.org/messenger/progress;1"].createInstance( + Ci.nsIMsgProgress + ); + let promise = new Promise((resolve, reject) => { + progressListener.resolve = resolve; + progressListener.reject = reject; + }); + progress.registerListener(progressListener); + msgCompose.sendMsg( + Ci.nsIMsgSend.nsMsgDeliverNow, + identity, + "", + null, + progress + ); + return promise; +} + +function checkDraftHeaders(expectedHeaders, partNum = "") { + let msgData = mailTestUtils.loadMessageToString( + gDraftFolder, + mailTestUtils.firstMsgHdr(gDraftFolder) + ); + checkMessageHeaders(msgData, expectedHeaders, partNum); +} + +function checkMessageHeaders(msgData, expectedHeaders, partNum = "") { + let seen = false; + let handler = { + startPart(part, headers) { + if (part != partNum) { + return; + } + seen = true; + for (let header in expectedHeaders) { + let expected = expectedHeaders[header]; + if (expected === undefined) { + Assert.ok( + !headers.has(header), + `Should not have header named "${header}"` + ); + } else { + let value = headers.getRawHeader(header); + Assert.equal( + value && value.length, + 1, + `Should have exactly one header named "${header}"` + ); + value[0] = value[0].replace(/boundary=[^;]*(;|$)/, "boundary=."); + Assert.equal(value[0], expected); + } + } + }, + }; + MimeParser.parseSync(msgData, handler, { + onerror(e) { + throw e; + }, + }); + Assert.ok(seen); +} + +async function testEnvelope() { + let fields = new CompFields(); + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + identity.fullName = "Me"; + identity.organization = "World Destruction Committee"; + fields.from = "Nobody <nobody@tinderbox.invalid>"; + fields.to = "Nobody <nobody@tinderbox.invalid>"; + fields.cc = "Alex <alex@tinderbox.invalid>"; + fields.bcc = "Boris <boris@tinderbox.invalid>"; + fields.replyTo = "Charles <charles@tinderbox.invalid>"; + fields.organization = "World Salvation Committee"; + fields.subject = "This is an obscure reference"; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + // As of bug 87987, the identity does not override the from header. + From: "Nobody <nobody@tinderbox.invalid>", + // The identity should override the organization field here. + Organization: "World Destruction Committee", + To: "Nobody <nobody@tinderbox.invalid>", + Cc: "Alex <alex@tinderbox.invalid>", + Bcc: "Boris <boris@tinderbox.invalid>", + "Reply-To": "Charles <charles@tinderbox.invalid>", + Subject: "This is an obscure reference", + }); +} + +async function testI18NEnvelope() { + let fields = new CompFields(); + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + identity.fullName = "ケツァルコアトル"; + identity.organization = "Comité de la destruction du monde"; + fields.to = "Émile <nobody@tinderbox.invalid>"; + fields.cc = "André Chopin <alex@tinderbox.invalid>"; + fields.bcc = "Étienne <boris@tinderbox.invalid>"; + fields.replyTo = "Frédéric <charles@tinderbox.invalid>"; + fields.subject = "Ceci n'est pas un référence obscure"; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + From: "=?UTF-8?B?44Kx44OE44Kh44Or44Kz44Ki44OI44Or?= <from@tinderbox.invalid>", + Organization: "=?UTF-8?Q?Comit=C3=A9_de_la_destruction_du_monde?=", + To: "=?UTF-8?B?w4ltaWxl?= <nobody@tinderbox.invalid>", + Cc: "=?UTF-8?Q?Andr=C3=A9_Chopin?= <alex@tinderbox.invalid>", + Bcc: "=?UTF-8?Q?=C3=89tienne?= <boris@tinderbox.invalid>", + "Reply-To": "=?UTF-8?B?RnLDqWTDqXJpYw==?= <charles@tinderbox.invalid>", + Subject: "=?UTF-8?Q?Ceci_n=27est_pas_un_r=C3=A9f=C3=A9rence_obscure?=", + }); +} + +async function testIDNEnvelope() { + let fields = new CompFields(); + let domain = "ケツァルコアトル.invalid"; + // We match against rawHeaderText, so we need to encode the string as a binary + // string instead of a unicode string. + let utf8Domain = String.fromCharCode.apply( + undefined, + new TextEncoder("UTF-8").encode(domain) + ); + // Bug 1034658: nsIMsgIdentity doesn't like IDN in its email addresses. + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + fields.to = "Nobody <nobody@" + domain + ">"; + fields.cc = "Alex <alex@" + domain + ">"; + fields.bcc = "Boris <boris@" + domain + ">"; + fields.replyTo = "Charles <charles@" + domain + ">"; + fields.subject = "This is an obscure reference"; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + // The identity sets the from field here. + From: "from@tinderbox.invalid", + To: "Nobody <nobody@" + utf8Domain + ">", + Cc: "Alex <alex@" + utf8Domain + ">", + Bcc: "Boris <boris@" + utf8Domain + ">", + "Reply-To": "Charles <charles@" + utf8Domain + ">", + Subject: "This is an obscure reference", + }); +} + +async function testDraftInfo() { + let fields = new CompFields(); + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + FCC: identity.fccFolder, + "X-Identity-Key": identity.key, + "X-Mozilla-Draft-Info": + "internal/draft; " + + "vcard=0; receipt=0; DSN=0; uuencode=0; attachmentreminder=0; deliveryformat=4", + }); + + fields.attachVCard = true; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "X-Mozilla-Draft-Info": + "internal/draft; " + + "vcard=1; receipt=0; DSN=0; uuencode=0; attachmentreminder=0; deliveryformat=4", + }); + + fields.returnReceipt = true; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "X-Mozilla-Draft-Info": + "internal/draft; " + + "vcard=1; receipt=1; DSN=0; uuencode=0; attachmentreminder=0; deliveryformat=4", + }); + + fields.DSN = true; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "X-Mozilla-Draft-Info": + "internal/draft; " + + "vcard=1; receipt=1; DSN=1; uuencode=0; attachmentreminder=0; deliveryformat=4", + }); + + fields.attachmentReminder = true; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "X-Mozilla-Draft-Info": + "internal/draft; " + + "vcard=1; receipt=1; DSN=1; uuencode=0; attachmentreminder=1; deliveryformat=4", + }); + + fields.deliveryFormat = Ci.nsIMsgCompSendFormat.Both; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "X-Mozilla-Draft-Info": + "internal/draft; " + + "vcard=1; receipt=1; DSN=1; uuencode=0; attachmentreminder=1; deliveryformat=3", + }); +} + +async function testOtherHeadersAgentParam(sendAgent, minimalAgent) { + Services.prefs.setBoolPref("mailnews.headers.sendUserAgent", sendAgent); + if (sendAgent) { + Services.prefs.setBoolPref( + "mailnews.headers.useMinimalUserAgent", + minimalAgent + ); + } + + let fields = new CompFields(); + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + fields.priority = "high"; + fields.references = "<fake@tinderbox.invalid> <more@test.invalid>"; + fields.setHeader("X-Fake-Header", "124"); + let before = Date.now(); + let msgHdr = await richCreateMessage(fields, [], identity); + let after = Date.now(); + let msgData = mailTestUtils.loadMessageToString(msgHdr.folder, msgHdr); + let expectedAgent = undefined; // !sendAgent + if (sendAgent) { + if (minimalAgent) { + expectedAgent = Services.strings + .createBundle("chrome://branding/locale/brand.properties") + .GetStringFromName("brandFullName"); + } else { + expectedAgent = Cc[ + "@mozilla.org/network/protocol;1?name=http" + ].getService(Ci.nsIHttpProtocolHandler).userAgent; + } + } + checkMessageHeaders(msgData, { + "Mime-Version": "1.0", + "User-Agent": expectedAgent, + "X-Priority": "2 (High)", + References: "<fake@tinderbox.invalid> <more@test.invalid>", + "In-Reply-To": "<more@test.invalid>", + "X-Fake-Header": "124", + }); + + // Check headers with dynamic content + let headers = MimeParser.extractHeaders(msgData); + Assert.ok(headers.has("Message-Id")); + Assert.ok( + headers.getRawHeader("Message-Id")[0].endsWith("@tinderbox.invalid>") + ); + // This is a very special crafted check. We don't know when the message was + // actually created, but we have bounds on it, from above. From + // experimentation, there are a few ways you can create dates that Date.parse + // can't handle (specifically related to how 2-digit years). However, the + // optimal RFC 5322 form is supported by Date.parse. If Date.parse fails, we + // have a form that we shouldn't be using anyways. + let date = new Date(headers.getRawHeader("Date")[0]); + // If we have clock skew within the test, then our results are going to be + // meaningless. Hopefully, this is only rarely the case. + if (before > after) { + info("Clock skew detected, skipping date check"); + } else { + // In case this all took place within one second, remove sub-millisecond + // timing (Date headers only carry second-level precision). + before = before - (before % 1000); + after = after - (after % 1000); + info(before + " <= " + date + " <= " + after + "?"); + Assert.ok(before <= date && date <= after); + } + + // We truncate too-long References. Check this. + let references = []; + for (let i = 0; i < 100; i++) { + references.push("<" + i + "@test.invalid>"); + } + let expected = references.slice(47); + expected.unshift(references[0]); + fields.references = references.join(" "); + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + References: expected.join(" "), + "In-Reply-To": references[references.length - 1], + }); +} + +/** + * Tests that the domain for the Message-Id header defaults to the domain of the + * identity's address. + */ +async function testMessageIdUseIdentityAddress() { + const expectedMessageIdHostname = "tinderbox.test"; + + const identity = getSmtpIdentity( + `from@${expectedMessageIdHostname}`, + getBasicSmtpServer() + ); + + await createMsgAndCompareMessageId(identity, null, expectedMessageIdHostname); +} + +/** + * Tests that if a custom address (with a custom domain) is used when composing a + * message, the domain in this address takes precendence over the domain of the + * identity's address to generate the value for the Message-Id header. + */ +async function testMessageIdUseFromDomain() { + const expectedMessageIdHostname = "another-tinderbox.test"; + + const identity = getSmtpIdentity("from@tinderbox.test", getBasicSmtpServer()); + + // Set the From header to an address that uses a different domain than + // the identity. + const fields = new CompFields(); + fields.from = `Nobody <nobody@${expectedMessageIdHostname}>`; + + await createMsgAndCompareMessageId( + identity, + fields, + expectedMessageIdHostname + ); +} + +/** + * Tests that if the identity has a "FQDN" attribute, it takes precedence to use as the + * domain for the Message-Id header over any other domain or address. + */ +async function testMessageIdUseIdentityAttribute() { + const expectedMessageIdHostname = "my-custom-fqdn.test"; + + const identity = getSmtpIdentity("from@tinderbox.test", getBasicSmtpServer()); + identity.setCharAttribute("FQDN", expectedMessageIdHostname); + + // Set the From header to an address that uses a different domain than + // the identity. + const fields = new CompFields(); + fields.from = "Nobody <nobody@another-tinderbox.test>"; + + await createMsgAndCompareMessageId( + identity, + fields, + expectedMessageIdHostname + ); +} + +/** + * Util function to create a message using the given identity and fields, + * and test that the message ID that was generated for it has the correct + * host name. + * + * @param {nsIMsgIdentity} identity - The identity to use to create the message. + * @param {?nsIMsgCompFields} fields - The compose fields to use. If not provided, + * default fields are used. + * @param {string} expectedMessageIdHostname - The expected host name of the + * Message-Id header. + */ +async function createMsgAndCompareMessageId( + identity, + fields, + expectedMessageIdHostname +) { + if (!fields) { + fields = new CompFields(); + } + + let msgHdr = await richCreateMessage(fields, [], identity); + let msgData = mailTestUtils.loadMessageToString(msgHdr.folder, msgHdr); + let headers = MimeParser.extractHeaders(msgData); + + // As of bug 1727181, the identity does not override the message-id header. + Assert.ok(headers.has("Message-Id"), "the message has a Message-Id header"); + Assert.ok( + headers + .getRawHeader("Message-Id")[0] + .endsWith(`@${expectedMessageIdHostname}>`), + `the hostname for the Message-Id header should be ${expectedMessageIdHostname}` + ); +} + +async function testOtherHeadersFullAgent() { + await testOtherHeadersAgentParam(true, false); +} + +async function testOtherHeadersMinimalAgent() { + await testOtherHeadersAgentParam(true, true); +} + +async function testOtherHeadersNoAgent() { + await testOtherHeadersAgentParam(false, undefined); +} + +async function testNewsgroups() { + let fields = new CompFields(); + let nntpServer = localAccountUtils.create_incoming_server( + "nntp", + 534, + "", + "" + ); + nntpServer + .QueryInterface(Ci.nsINntpIncomingServer) + .subscribeToNewsgroup("mozilla.test"); + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + fields.newsgroups = "mozilla.test, mozilla.test.multimedia"; + fields.followupTo = "mozilla.test"; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + // The identity should override the compose fields here. + Newsgroups: "mozilla.test,mozilla.test.multimedia", + "Followup-To": "mozilla.test", + "X-Mozilla-News-Host": "localhost", + }); +} + +async function testSendHeaders() { + let fields = new CompFields(); + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + identity.setCharAttribute("headers", "bah,humbug"); + identity.setCharAttribute( + "header.bah", + "X-Custom-1: A header value: with a colon" + ); + identity.setUnicharAttribute("header.humbug", "X-Custom-2: Enchanté"); + identity.setCharAttribute("subscribed_mailing_lists", "list@test.invalid"); + identity.setCharAttribute( + "replyto_mangling_mailing_lists", + "replyto@test.invalid" + ); + fields.to = "list@test.invalid"; + fields.cc = "not-list@test.invalid"; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "X-Custom-1": "A header value: with a colon", + "X-Custom-2": "=?UTF-8?B?RW5jaGFudMOp?=", + "Mail-Followup-To": "list@test.invalid, not-list@test.invalid", + "Mail-Reply-To": undefined, + }); + + // Don't set the M-F-T header if there's no list. + fields.to = "replyto@test.invalid"; + fields.cc = ""; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "X-Custom-1": "A header value: with a colon", + "X-Custom-2": "=?UTF-8?B?RW5jaGFudMOp?=", + "Mail-Reply-To": "from@tinderbox.invalid", + "Mail-Followup-To": undefined, + }); +} + +async function testContentHeaders() { + // Disable RFC 2047 fallback + Services.prefs.setIntPref("mail.strictly_mime.parm_folding", 2); + let fields = new CompFields(); + fields.body = "A body"; + let identity = getSmtpIdentity( + "from@tinderbox.invalid", + getBasicSmtpServer() + ); + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "Content-Type": "text/html; charset=UTF-8", + "Content-Transfer-Encoding": "7bit", + }); + + // non-ASCII body should be 8-bit... + fields.body = "Archæologist"; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "Content-Type": "text/html; charset=UTF-8", + "Content-Transfer-Encoding": "8bit", + }); + + // Attachments + fields.body = ""; + let plainAttachment = makeAttachment({ + url: "data:text/plain,oïl", + name: "attachment.txt", + }); + let plainAttachmentHeaders = { + "Content-Type": "text/plain; charset=UTF-8", + "Content-Transfer-Encoding": "base64", + "Content-Disposition": 'attachment; filename="attachment.txt"', + }; + await richCreateMessage(fields, [plainAttachment], identity); + checkDraftHeaders( + { + "Content-Type": "text/html; charset=UTF-8", + "Content-Transfer-Encoding": "7bit", + }, + "1" + ); + checkDraftHeaders(plainAttachmentHeaders, "2"); + + plainAttachment.name = "oïl.txt"; + plainAttachmentHeaders["Content-Disposition"] = + "attachment; filename*=UTF-8''%6F%C3%AF%6C%2E%74%78%74"; + await richCreateMessage(fields, [plainAttachment], identity); + checkDraftHeaders(plainAttachmentHeaders, "2"); + + plainAttachment.name = "\ud83d\udca9.txt"; + plainAttachmentHeaders["Content-Disposition"] = + "attachment; filename*=UTF-8''%F0%9F%92%A9%2E%74%78%74"; + await richCreateMessage(fields, [plainAttachment], identity); + checkDraftHeaders(plainAttachmentHeaders, "2"); + + let httpAttachment = makeAttachment({ + url: "data:text/html,<html></html>", + name: "attachment.html", + }); + let httpAttachmentHeaders = { + "Content-Type": "text/html; charset=UTF-8", + "Content-Disposition": 'attachment; filename="attachment.html"', + "Content-Location": "data:text/html,<html></html>", + }; + await richCreateMessage(fields, [httpAttachment], identity); + checkDraftHeaders( + { + "Content-Location": undefined, + }, + "1" + ); + checkDraftHeaders(httpAttachmentHeaders, "2"); + + let cloudAttachment = makeAttachment({ + url: Services.io.newFileURI(do_get_file("data/test-UTF-8.txt")).spec, + sendViaCloud: true, + htmlAnnotation: + "<html><body>This is an html placeholder file.</body></html>", + cloudFileAccountKey: "akey", + cloudPartHeaderData: "0123456789ABCDE", + name: "attachment.html", + contentLocation: "http://localhost.invalid/", + }); + let cloudAttachmentHeaders = { + "Content-Type": "text/html; charset=utf-8", + "X-Mozilla-Cloud-Part": + "cloudFile; " + + "url=http://localhost.invalid/; " + + "provider=akey; " + + 'data="0123456789ABCDE"', + }; + await richCreateMessage(fields, [cloudAttachment], identity); + checkDraftHeaders(cloudAttachmentHeaders, "2"); + + // Cloud attachment with non-ascii file name. + cloudAttachment = makeAttachment({ + url: Services.io.newFileURI(do_get_file("data/test-UTF-8.txt")).spec, + sendViaCloud: true, + htmlAnnotation: + "<html><body>This is an html placeholder file.</body></html>", + cloudFileAccountKey: "akey", + cloudPartHeaderData: "0123456789ABCDE", + name: "ファイル.txt", + contentLocation: "http://localhost.invalid/", + }); + cloudAttachmentHeaders = { + "Content-Type": "text/html; charset=utf-8", + "X-Mozilla-Cloud-Part": + "cloudFile; " + + "url=http://localhost.invalid/; " + + "provider=akey; " + + 'data="0123456789ABCDE"', + }; + await richCreateMessage(fields, [cloudAttachment], identity); + checkDraftHeaders(cloudAttachmentHeaders, "2"); + + // Some multipart/alternative tests. + fields.body = "Some text"; + fields.forcePlainText = false; + fields.useMultipartAlternative = true; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "Content-Type": "multipart/alternative; boundary=.", + }); + checkDraftHeaders( + { + "Content-Type": "text/plain; charset=UTF-8; format=flowed", + "Content-Transfer-Encoding": "7bit", + }, + "1" + ); + checkDraftHeaders( + { + "Content-Type": "text/html; charset=UTF-8", + "Content-Transfer-Encoding": "7bit", + }, + "2" + ); + + // multipart/mixed + // + multipart/alternative + // + text/plain + // + text/html + // + text/plain attachment + await richCreateMessage(fields, [plainAttachment], identity); + checkDraftHeaders({ + "Content-Type": "multipart/mixed; boundary=.", + }); + checkDraftHeaders( + { + "Content-Type": "multipart/alternative; boundary=.", + }, + "1" + ); + checkDraftHeaders( + { + "Content-Type": "text/plain; charset=UTF-8; format=flowed", + "Content-Transfer-Encoding": "7bit", + }, + "1.1" + ); + checkDraftHeaders( + { + "Content-Type": "text/html; charset=UTF-8", + "Content-Transfer-Encoding": "7bit", + }, + "1.2" + ); + checkDraftHeaders(plainAttachmentHeaders, "2"); + + // Three attachments, and a multipart/alternative. Oh the humanity! + await richCreateMessage( + fields, + [plainAttachment, httpAttachment, cloudAttachment], + identity + ); + checkDraftHeaders({ + "Content-Type": "multipart/mixed; boundary=.", + }); + checkDraftHeaders( + { + "Content-Type": "multipart/alternative; boundary=.", + }, + "1" + ); + checkDraftHeaders( + { + "Content-Type": "text/plain; charset=UTF-8; format=flowed", + "Content-Transfer-Encoding": "7bit", + }, + "1.1" + ); + checkDraftHeaders( + { + "Content-Type": "text/html; charset=UTF-8", + "Content-Transfer-Encoding": "7bit", + }, + "1.2" + ); + checkDraftHeaders(plainAttachmentHeaders, "2"); + checkDraftHeaders(httpAttachmentHeaders, "3"); + checkDraftHeaders(cloudAttachmentHeaders, "4"); + + // Test a request for plain text with text/html. + fields.forcePlainText = true; + fields.useMultipartAlternative = false; + await richCreateMessage(fields, [], identity); + checkDraftHeaders({ + "Content-Type": "text/plain; charset=UTF-8; format=flowed", + "Content-Transfer-Encoding": "7bit", + }); +} + +async function testSentMessage() { + let server = setupServerDaemon(); + let daemon = server._daemon; + server.start(); + try { + let localserver = getBasicSmtpServer(server.port); + let identity = getSmtpIdentity("test@tinderbox.invalid", localserver); + await sendMessage( + { + to: "Nobody <nobody@tinderbox.invalid>", + cc: "Alex <alex@tinderbox.invalid>", + bcc: "Boris <boris@tinderbox.invalid>", + replyTo: "Charles <charles@tinderbox.invalid>", + }, + identity, + {}, + [] + ); + checkMessageHeaders(daemon.post, { + From: "test@tinderbox.invalid", + To: "Nobody <nobody@tinderbox.invalid>", + Cc: "Alex <alex@tinderbox.invalid>", + Bcc: undefined, + "Reply-To": "Charles <charles@tinderbox.invalid>", + "X-Mozilla-Status": undefined, + "X-Mozilla-Keys": undefined, + "X-Mozilla-Draft-Info": undefined, + Fcc: undefined, + }); + server.resetTest(); + await sendMessage({ bcc: "Somebody <test@tinderbox.invalid" }, identity); + checkMessageHeaders(daemon.post, { + To: "undisclosed-recipients: ;", + }); + server.resetTest(); + await sendMessage( + { + to: "Somebody <test@tinderbox.invalid>", + returnReceipt: true, + receiptHeaderType: Ci.nsIMsgMdnGenerator.eDntRrtType, + }, + identity + ); + checkMessageHeaders(daemon.post, { + "Disposition-Notification-To": "test@tinderbox.invalid", + "Return-Receipt-To": "test@tinderbox.invalid", + }); + server.resetTest(); + let cloudAttachment = makeAttachment({ + url: Services.io.newFileURI(do_get_file("data/test-UTF-8.txt")).spec, + sendViaCloud: true, + htmlAnnotation: + "<html><body>This is an html placeholder file.</body></html>", + cloudFileAccountKey: "akey", + cloudPartHeaderData: "0123456789ABCDE", + name: "attachment.html", + contentLocation: "http://localhost.invalid/", + }); + await sendMessage({ to: "test@tinderbox.invalid" }, identity, {}, [ + cloudAttachment, + ]); + checkMessageHeaders( + daemon.post, + { + "Content-Type": "text/html; charset=utf-8", + "X-Mozilla-Cloud-Part": "cloudFile; url=http://localhost.invalid/", + }, + "2" + ); + } finally { + server.stop(); + } +} + +var tests = [ + testEnvelope, + testI18NEnvelope, + testIDNEnvelope, + testDraftInfo, + testOtherHeadersFullAgent, + testOtherHeadersMinimalAgent, + testOtherHeadersNoAgent, + testNewsgroups, + testSendHeaders, + testContentHeaders, + testSentMessage, + testMessageIdUseIdentityAddress, + testMessageIdUseFromDomain, + testMessageIdUseIdentityAttribute, +]; + +function run_test() { + // Ensure we have at least one mail account + localAccountUtils.loadLocalMailAccount(); + tests.forEach(x => add_task(x)); + run_next_test(); +} |