From 5a663af4cd7a30381a1d57407705af7ff0fe93f1 Mon Sep 17 00:00:00 2001 From: Rob Wood Date: Thu, 11 Mar 2021 09:29:00 +0000 Subject: [PATCH] Fix broken tests. --- .../MessagesControllerTests.cs | 166 +++---- Rnwood.Smtp4dev/ClientApp/package-lock.json | 426 +++++++++--------- Rnwood.Smtp4dev/Server/MessageConverter.cs | 93 ++-- Rnwood.Smtp4dev/Server/Smtp4devServer.cs | 74 ++- 4 files changed, 386 insertions(+), 373 deletions(-) diff --git a/Rnwood.Smtp4dev.Tests/MessagesControllerTests.cs b/Rnwood.Smtp4dev.Tests/MessagesControllerTests.cs index 4f9b1c653..d341bdeb5 100644 --- a/Rnwood.Smtp4dev.Tests/MessagesControllerTests.cs +++ b/Rnwood.Smtp4dev.Tests/MessagesControllerTests.cs @@ -1,6 +1,7 @@ using MimeKit; using Rnwood.Smtp4dev.Controllers; using Rnwood.Smtp4dev.Server; +using Rnwood.SmtpServer; using System; using System.IO; using System.Linq; @@ -10,83 +11,92 @@ namespace Rnwood.Smtp4dev.Tests { - public class MessagesControllerTests - { - [Fact] - public async Task GetMessage_ValidMime() - { - DateTime startDate = DateTime.Now; - DbModel.Message testMessage1 = await GetTestMessage1(); - - TestMessagesRepository messagesRepository = new TestMessagesRepository(testMessage1); - MessagesController messagesController = new MessagesController(messagesRepository, null); - - ApiModel.Message result = messagesController.GetMessage(testMessage1.Id); - - Assert.Null(result.MimeParseError); - Assert.Equal(testMessage1.Id, result.Id); - Assert.InRange(result.ReceivedDate, startDate, DateTime.Now); - Assert.Equal("from@message.com", result.From); - Assert.Equal("to@message.com", result.To); - Assert.Equal("to@envelope.com", result.Bcc); - Assert.Equal("cc@message.com", result.Cc); - Assert.Equal("subject", result.Subject); - - var allParts = result.Parts.Flatten(p => p.ChildParts).ToList(); - Assert.Equal(6, allParts.Count); - - - Assert.All(allParts, p => { - Assert.Equal(testMessage1.Id, p.MessageId); - Assert.NotNull(p.Id); - Assert.NotEqual("", p.Id); - }); - - //All parts have a unique Id - Assert.Equal(allParts.Count, allParts.Select(p => p.Id).Distinct().Count()); - - } - - private static readonly string testMessage1File1Content = "111"; - private static readonly string testMessage1File2Content = "222"; - - private static async Task GetTestMessage1() - { - MimeMessage message = new MimeMessage(); - message.From.Add(InternetAddress.Parse("from@message.com")); - message.To.Add(InternetAddress.Parse("to@message.com")); - message.Cc.Add(InternetAddress.Parse("cc@message.com")); - - message.Subject = "subject"; - BodyBuilder bodyBuilder = new BodyBuilder(); - bodyBuilder.HtmlBody = "Hi"; - bodyBuilder.TextBody = "Hi"; - bodyBuilder.Attachments.Add("file1", new MemoryStream(System.Text.Encoding.UTF8.GetBytes(testMessage1File1Content)), new ContentType("text", "plain")).ContentId = "file1"; - bodyBuilder.Attachments.Add("file2", new MemoryStream(System.Text.Encoding.UTF8.GetBytes(testMessage1File2Content)), new ContentType("text", "plain")); - - message.Body = bodyBuilder.ToMessageBody(); - - var dbMessage = await new MessageConverter().ConvertAsync( -new MemoryStream(Encoding.UTF8.GetBytes(message.ToString())), "from@envelope.com", "to@envelope.com"); - return dbMessage; - } - - [Fact] - public async Task GetPartContent() - { - DbModel.Message testMessage1 = await GetTestMessage1(); - TestMessagesRepository messagesRepository = new TestMessagesRepository(testMessage1); - MessagesController messagesController = new MessagesController(messagesRepository, null); - - var parts = messagesController.GetMessage(testMessage1.Id).Parts.Flatten(p => p.ChildParts).SelectMany(p => p.Attachments); - - var part = parts.First(p => p.FileName == "file2"); - - var result = messagesController.GetPartContent(testMessage1.Id, part.Id); - var stringResult = await new StreamReader(result.FileStream, Encoding.UTF8).ReadToEndAsync(); - - Assert.Equal(testMessage1File2Content, stringResult); - } - } + public class MessagesControllerTests + { + [Fact] + public async Task GetMessage_ValidMime() + { + DateTime startDate = DateTime.Now; + DbModel.Message testMessage1 = await GetTestMessage1(); + + TestMessagesRepository messagesRepository = new TestMessagesRepository(testMessage1); + MessagesController messagesController = new MessagesController(messagesRepository, null); + + ApiModel.Message result = messagesController.GetMessage(testMessage1.Id); + + Assert.Null(result.MimeParseError); + Assert.Equal(testMessage1.Id, result.Id); + Assert.InRange(result.ReceivedDate, startDate, DateTime.Now); + Assert.Equal("from@message.com", result.From); + Assert.Equal("to@message.com", result.To); + Assert.Equal("to@envelope.com", result.Bcc); + Assert.Equal("cc@message.com", result.Cc); + Assert.Equal("subject", result.Subject); + + var allParts = result.Parts.Flatten(p => p.ChildParts).ToList(); + Assert.Equal(6, allParts.Count); + + + Assert.All(allParts, p => + { + Assert.Equal(testMessage1.Id, p.MessageId); + Assert.NotNull(p.Id); + Assert.NotEqual("", p.Id); + }); + + //All parts have a unique Id + Assert.Equal(allParts.Count, allParts.Select(p => p.Id).Distinct().Count()); + + } + + private static readonly string testMessage1File1Content = "111"; + private static readonly string testMessage1File2Content = "222"; + + private static async Task GetTestMessage1() + { + MimeMessage mimeMessage = new MimeMessage(); + mimeMessage.From.Add(InternetAddress.Parse("from@message.com")); + mimeMessage.To.Add(InternetAddress.Parse("to@message.com")); + mimeMessage.Cc.Add(InternetAddress.Parse("cc@message.com")); + + mimeMessage.Subject = "subject"; + BodyBuilder bodyBuilder = new BodyBuilder(); + bodyBuilder.HtmlBody = "Hi"; + bodyBuilder.TextBody = "Hi"; + bodyBuilder.Attachments.Add("file1", new MemoryStream(System.Text.Encoding.UTF8.GetBytes(testMessage1File1Content)), new ContentType("text", "plain")).ContentId = "file1"; + bodyBuilder.Attachments.Add("file2", new MemoryStream(System.Text.Encoding.UTF8.GetBytes(testMessage1File2Content)), new ContentType("text", "plain")); + + mimeMessage.Body = bodyBuilder.ToMessageBody(); + + MemoryMessageBuilder memoryMessageBuilder = new MemoryMessageBuilder(); + memoryMessageBuilder.Recipients.Add("to@envelope.com"); + memoryMessageBuilder.From = "from@envelope.com"; + using (var messageData = await memoryMessageBuilder.WriteData()) + { + messageData.Write(Encoding.UTF8.GetBytes(mimeMessage.ToString())); + } + IMessage message = await memoryMessageBuilder.ToMessage(); + + var dbMessage = await new MessageConverter().ConvertAsync(message); + return dbMessage; + } + + [Fact] + public async Task GetPartContent() + { + DbModel.Message testMessage1 = await GetTestMessage1(); + TestMessagesRepository messagesRepository = new TestMessagesRepository(testMessage1); + MessagesController messagesController = new MessagesController(messagesRepository, null); + + var parts = messagesController.GetMessage(testMessage1.Id).Parts.Flatten(p => p.ChildParts).SelectMany(p => p.Attachments); + + var part = parts.First(p => p.FileName == "file2"); + + var result = messagesController.GetPartContent(testMessage1.Id, part.Id); + var stringResult = await new StreamReader(result.FileStream, Encoding.UTF8).ReadToEndAsync(); + + Assert.Equal(testMessage1File2Content, stringResult); + } + } } diff --git a/Rnwood.Smtp4dev/ClientApp/package-lock.json b/Rnwood.Smtp4dev/ClientApp/package-lock.json index 592976114..de1497802 100644 --- a/Rnwood.Smtp4dev/ClientApp/package-lock.json +++ b/Rnwood.Smtp4dev/ClientApp/package-lock.json @@ -3069,6 +3069,13 @@ "yorkie": "^2.0.0" }, "dependencies": { + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true, + "optional": true + }, "@vue/cli-shared-utils": { "version": "4.5.11", "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-4.5.11.tgz", @@ -3089,11 +3096,217 @@ "strip-ansi": "^6.0.0" } }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "optional": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "optional": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "optional": true + }, + "fork-ts-checker-webpack-plugin-v5": { + "version": "npm:fork-ts-checker-webpack-plugin@5.2.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", + "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", + "dev": true, + "optional": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "optional": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "optional": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "optional": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "optional": true + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "optional": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "optional": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "optional": true } } }, @@ -7493,219 +7706,6 @@ } } }, - "fork-ts-checker-webpack-plugin-v5": { - "version": "npm:fork-ts-checker-webpack-plugin@5.2.1", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", - "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", - "dev": true, - "optional": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "dependencies": { - "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", - "dev": true, - "optional": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "optional": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "optional": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "optional": true - }, - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "optional": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "optional": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "optional": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "optional": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "optional": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "optional": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "optional": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "optional": true - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "optional": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "optional": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true - } - } - }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", diff --git a/Rnwood.Smtp4dev/Server/MessageConverter.cs b/Rnwood.Smtp4dev/Server/MessageConverter.cs index f111f289a..6e84b11e6 100644 --- a/Rnwood.Smtp4dev/Server/MessageConverter.cs +++ b/Rnwood.Smtp4dev/Server/MessageConverter.cs @@ -11,81 +11,86 @@ namespace Rnwood.Smtp4dev.Server { public class MessageConverter { - public async Task ConvertAsync(Stream messageData, IMessage messageEnvelope) + public async Task ConvertAsync(IMessage message) { string subject = ""; string mimeParseError = null; - string toAddress = string.Join(", ", messageEnvelope.Recipients); + string toAddress = string.Join(", ", message.Recipients); - byte[] data = new byte[messageData.Length]; - await messageData.ReadAsync(data, 0, data.Length); + byte[] data; + using (Stream messageData = await message.GetData()) + { + data = new byte[messageData.Length]; + await messageData.ReadAsync(data, 0, data.Length); - bool foundHeaders = false; - bool foundSeparator = false; - using (StreamReader dataReader = new StreamReader(new MemoryStream(data))) - { - while (!dataReader.EndOfStream) + + bool foundHeaders = false; + bool foundSeparator = false; + using (StreamReader dataReader = new StreamReader(new MemoryStream(data))) { - if (dataReader.ReadLine().Length != 0) + while (!dataReader.EndOfStream) { - foundHeaders = true; - } - else - { - foundSeparator = true; - break; + if (dataReader.ReadLine().Length != 0) + { + foundHeaders = true; + } + else + { + foundSeparator = true; + break; + } } } - } - if (!foundHeaders || !foundSeparator) - { - mimeParseError = "Malformed MIME message. No headers found"; - } - else - { - - messageData.Seek(0, SeekOrigin.Begin); - try + if (!foundHeaders || !foundSeparator) { - CancellationTokenSource cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromSeconds(10)); - MimeMessage mime = await MimeMessage.LoadAsync(messageData, true, cts.Token).ConfigureAwait(false); - subject = mime.Subject; - - + mimeParseError = "Malformed MIME message. No headers found"; } - catch (OperationCanceledException e) + else { - mimeParseError = e.Message; - } - catch (FormatException e) - { - mimeParseError = e.Message; + + messageData.Seek(0, SeekOrigin.Begin); + try + { + CancellationTokenSource cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(10)); + MimeMessage mime = await MimeMessage.LoadAsync(messageData, true, cts.Token).ConfigureAwait(false); + subject = mime.Subject; + + + } + catch (OperationCanceledException e) + { + mimeParseError = e.Message; + } + catch (FormatException e) + { + mimeParseError = e.Message; + } } } - var message = new DbModel.Message + DbModel.Message result = new DbModel.Message { Id = Guid.NewGuid(), - From = PunyCodeReplacer.DecodePunycode(messageEnvelope.From), + From = PunyCodeReplacer.DecodePunycode(message.From), To = PunyCodeReplacer.DecodePunycode(toAddress), ReceivedDate = DateTime.Now, Subject = PunyCodeReplacer.DecodePunycode(subject), Data = data, MimeParseError = mimeParseError, AttachmentCount = 0, - SecureConnection = messageEnvelope.SecureConnection + SecureConnection = message.SecureConnection }; - var parts = new Message(message).Parts; + var parts = new Message(result).Parts; foreach (var part in parts) { - message.AttachmentCount += CountAttachments(part); + result.AttachmentCount += CountAttachments(part); } - return message; + return result; } private int CountAttachments(MessageEntitySummary part) diff --git a/Rnwood.Smtp4dev/Server/Smtp4devServer.cs b/Rnwood.Smtp4dev/Server/Smtp4devServer.cs index 865a35ad9..d3a709f67 100644 --- a/Rnwood.Smtp4dev/Server/Smtp4devServer.cs +++ b/Rnwood.Smtp4dev/Server/Smtp4devServer.cs @@ -279,39 +279,36 @@ internal Task DeleteAllSessions() private async Task OnMessageReceived(object sender, MessageEventArgs e) { - using (Stream stream = e.Message.GetData().Result) - { - Message message = new MessageConverter().ConvertAsync(stream, e.Message).Result; - Console.WriteLine($"Message received. Client address {e.Message.Session.ClientAddress}. From {e.Message.From}. To {message.To}."); - message.IsUnread = true; + Message message = new MessageConverter().ConvertAsync(e.Message).Result; + Console.WriteLine($"Message received. Client address {e.Message.Session.ClientAddress}. From {e.Message.From}. To {message.To}."); + message.IsUnread = true; - await taskQueue.QueueTask(() => - { - Console.WriteLine("Processing received message"); - Smtp4devDbContext dbContext = dbContextFactory(); + await taskQueue.QueueTask(() => + { + Console.WriteLine("Processing received message"); + Smtp4devDbContext dbContext = dbContextFactory(); - Dictionary relayErrors = TryRelayMessage(message, null); - message.RelayError = string.Join("\n", relayErrors.Select(e => e.Key.ToString() + ": " + e.Value.Message)); + Dictionary relayErrors = TryRelayMessage(message, null); + message.RelayError = string.Join("\n", relayErrors.Select(e => e.Key.ToString() + ": " + e.Value.Message)); - ImapState imapState = dbContext.ImapState.Single(); - imapState.LastUid = Math.Max(0, imapState.LastUid+1); - message.ImapUid = imapState.LastUid; + ImapState imapState = dbContext.ImapState.Single(); + imapState.LastUid = Math.Max(0, imapState.LastUid + 1); + message.ImapUid = imapState.LastUid; - Session dbSession = dbContext.Sessions.Find(activeSessionsToDbId[e.Message.Session]); - message.Session = dbSession; - dbContext.Messages.Add(message); + Session dbSession = dbContext.Sessions.Find(activeSessionsToDbId[e.Message.Session]); + message.Session = dbSession; + dbContext.Messages.Add(message); - dbContext.SaveChanges(); + dbContext.SaveChanges(); - TrimMessages(dbContext); - dbContext.SaveChanges(); - notificationsHub.OnMessagesChanged().Wait(); - Console.WriteLine("Processing received message DONE"); + TrimMessages(dbContext); + dbContext.SaveChanges(); + notificationsHub.OnMessagesChanged().Wait(); + Console.WriteLine("Processing received message DONE"); - }, false).ConfigureAwait(false); - } + }, false).ConfigureAwait(false); } public Dictionary TryRelayMessage(Message message, MailboxAddress[] overrideRecipients) @@ -332,7 +329,8 @@ private async Task OnMessageReceived(object sender, MessageEventArgs e) .Select(r => MailboxAddress.Parse(r)) .Where(r => relayOptions.CurrentValue.AutomaticEmails.Contains(r.Address, StringComparer.OrdinalIgnoreCase)) .ToArray(); - } else + } + else { recipients = overrideRecipients; } @@ -341,20 +339,20 @@ private async Task OnMessageReceived(object sender, MessageEventArgs e) { try { - - Console.WriteLine($"Relaying message to {recipient}"); - using (SmtpClient relaySmtpClient = relaySmtpClientFactory(relayOptions.CurrentValue)) - { - var apiMsg = new ApiModel.Message(message); - MimeMessage newEmail = apiMsg.MimeMessage; - MailboxAddress sender = MailboxAddress.Parse( - !string.IsNullOrEmpty(relayOptions.CurrentValue.SenderAddress) - ? relayOptions.CurrentValue.SenderAddress - : apiMsg.From); - relaySmtpClient.Send(newEmail, sender, new[] { recipient }); - } - + Console.WriteLine($"Relaying message to {recipient}"); + + using (SmtpClient relaySmtpClient = relaySmtpClientFactory(relayOptions.CurrentValue)) + { + var apiMsg = new ApiModel.Message(message); + MimeMessage newEmail = apiMsg.MimeMessage; + MailboxAddress sender = MailboxAddress.Parse( + !string.IsNullOrEmpty(relayOptions.CurrentValue.SenderAddress) + ? relayOptions.CurrentValue.SenderAddress + : apiMsg.From); + relaySmtpClient.Send(newEmail, sender, new[] { recipient }); + } + } catch (Exception e)