public void AttachmentsShouldBeCorrectlyParsed()
        {
            var parser = new SendgridEmailParser();

            using (var form = Build(new Dictionary <string, object>
            {
                { "from", "from <*****@*****.**>" },
                { "to", "no name <*****@*****.**>" },
                { "subject", "subj" },
                { "html", "other content" },
                { "attachment-info", JsonConvert.SerializeObject(new
                    {
                        attachment1 = new
                        {
                            filename = "en.txt",
                            type = "text/plain"
                        },
                        attachment2 = new
                        {
                            filename = "img.jpg",
                            type = "image/jpeg"
                        }
                    }) },
                { "attachment1", new EmailAttachment
                  {
                      FileName = "en.txt",
                      ContentType = "text/plain",
                      Base64Data = "This is the actual content"
                  } },
                { "attachment2", new EmailAttachment
                  {
                      FileName = "img.jpg",
                      ContentType = "image/jpeg",
                      Base64Data = "large base64 payload"
                  } }
            }))
            {
                var result = parser.Parse(form);
                result.From.Email.Should().Be("*****@*****.**");
                result.To[0].Email.Should().Be("*****@*****.**");
                result.Subject.Should().Be("subj");
                result.Html.Should().Be("other content");
                result.Attachments.Should().HaveCount(2);
                result.Attachments[0].ContentType.Should().Be("text/plain");
                result.Attachments[0].FileName.Should().Be("en.txt");
                result.Attachments[0].Base64Data.Should().Be(Convert.ToBase64String(Encoding.UTF8.GetBytes("This is the actual content")));
                result.Attachments[1].ContentType.Should().Be("image/jpeg");
                result.Attachments[1].FileName.Should().Be("img.jpg");
                result.Attachments[1].Base64Data.Should().Be(Convert.ToBase64String(Encoding.UTF8.GetBytes("large base64 payload")));
            }
        }
        public void HtmlShouldBePreferredOverText()
        {
            var parser = new SendgridEmailParser();

            const string actualContent = "Only this should be submitted";
            var          data          = new Dictionary <string, object>
            {
                { "from", "from <*****@*****.**>" },
                { "to", "no name <*****@*****.**>" },
                { "subject", "subj" },
                { "text", "other content" },
                { "html", @"<html>
<head>
<meta http-equiv=""Content-Type"" content=""text/html; charset=iso-8859-1"">
<style type=""text/css"" style=""display:none;""> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir=""ltr"">
<div style=""font-family:Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)"">" +
                  actualContent +
                  @"<br>
</div>
<div style=""font-family:Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)"">
</div>
<div style=""font-family:Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)"">
<br>
</div>
<div id=""Signature"">
<div id=""divtagdefaultwrapper"" style=""font-size:12pt; color:#000000; font-family:Calibri,Arial,Helvetica,sans-serif"">
Regards,
<div>Sender</div>
</div>
</div>
</body>
</html>" }
            };

            using (var form = Build(data))
            {
                var result = parser.Parse(form);
                result.From.Email.Should().Be("*****@*****.**");
                result.To[0].Email.Should().Be("*****@*****.**");
                result.Subject.Should().Be("subj");
                result.Html.Should().Be((string)data["html"]);
            }
        }
        public void ParsingDisplayNamesShouldWork()
        {
            var parser = new SendgridEmailParser();

            using (var form = Build(new Dictionary <string, object>
            {
                { "from", "from <*****@*****.**>" },
                { "to", "no name <*****@*****.**>" },
                { "subject", "subj" },
                { "html", "text" }
            }))
            {
                var result = parser.Parse(form);
                result.From.Email.Should().Be("*****@*****.**");
                result.To[0].Email.Should().Be("*****@*****.**");
                result.Subject.Should().Be("subj");
                result.Html.Should().Be("text");
            }
        }
        public void TextShouldBeFallbackIfHtmlFails()
        {
            var parser = new SendgridEmailParser();

            using (var form = Build(new Dictionary <string, object>
            {
                { "from", "from <*****@*****.**>" },
                { "to", "no name <*****@*****.**>" },
                { "subject", "subj" },
                { "text", "other content" },
                { "html", "" }
            }))
            {
                var result = parser.Parse(form);
                result.From.Email.Should().Be("*****@*****.**");
                result.To[0].Email.Should().Be("*****@*****.**");
                result.Subject.Should().Be("subj");
                result.Html.Should().Be("");
                result.Text.Should().Be("other content");
            }
        }
        public void AttachmentsShouldBeCorrectlyParsedFromActualPayload()
        {
            var parser = new SendgridEmailParser();

            using (var form = new MemoryStream())
            {
                var content = File.ReadAllText("Data/multipart.txt");
                var writer  = new StreamWriter(form);
                writer.Write(content);
                writer.Flush();
                form.Position = 0;
                var result = parser.Parse(form);
                result.From.Email.Should().Be("*****@*****.**");
                result.From.Name.Should().Be("Marc Stan");
                result.To[0].Email.Should().Be("*****@*****.**");
                result.To[0].Name.Should().Be("*****@*****.**");
                result.Subject.Should().Be("Subject1");
                result.Text.Should().Be("Content1");
                result.Attachments.Should().HaveCount(1);
                result.Attachments[0].ContentType.Should().Be("text/plain");
                result.Attachments[0].FileName.Should().Be("en.txt");
                result.Attachments[0].Base64Data.Should().Be(Convert.ToBase64String(Encoding.UTF8.GetBytes("this is plaintext")));
            }
        }
Example #6
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
            Microsoft.Azure.WebJobs.ExecutionContext context,
            ILogger log,
            CancellationToken cancellationToken)
        {
            try
            {
                var config = LoadConfig(context.FunctionAppDirectory, log);

                var container = config["ArchiveContainerName"];
                var target    = config["RelayTargetEmail"];
                if (string.IsNullOrEmpty(container) && string.IsNullOrEmpty(target))
                {
                    throw new NotSupportedException("Neither email target nor container name where set. Please set either ArchiveContainerName or RelayTargetEmail");
                }

                Email email;
                using (var stream = new MemoryStream())
                {
                    // body can only be read once
                    req.Body.CopyTo(stream);
                    stream.Position = 0;
                    var parser = new SendgridEmailParser();
                    email = parser.Parse(stream);
                }
                if (!string.IsNullOrEmpty(container))
                {
                    IPersister auditLogger = new BlobStoragePersister(config["AzureWebJobsStorage"], container);

                    var d = DateTimeOffset.UtcNow;
                    // one folder per day is fine for now
                    var id = $"{d.ToString("yyyy-MM")}/{d.ToString("dd")}/{d.ToString("HH-mm-ss")}_{email.From.Email} - {email.Subject}";
                    await auditLogger.PersistAsync($"{id}.json", JsonConvert.SerializeObject(email, Formatting.Indented));

                    // save all attachments in subfolder
                    await Task.WhenAll(email.Attachments.Select(a => auditLogger.PersistAsync($"{id} (Attachments)/{a.FileName}", Convert.FromBase64String(a.Base64Data))));
                }
                if (!string.IsNullOrEmpty(target))
                {
                    var domain = config["Domain"];
                    var key    = config["SendgridApiKey"];
                    if (!string.IsNullOrEmpty(target) &&
                        string.IsNullOrEmpty(domain))
                    {
                        throw new NotSupportedException("Domain must be set as well when relay is used.");
                    }
                    if (!string.IsNullOrEmpty(target) &&
                        string.IsNullOrEmpty(key))
                    {
                        throw new NotSupportedException("SendgridApiKey must be set as well when relay is used.");
                    }

                    var client        = new SendGridClient(key);
                    var subjectParser = new SubjectParser(config["Prefix"]);
                    var relay         = new RelayLogic(client, subjectParser, log, new[]
                    {
                        new OutlookWebSanitizer(subjectParser)
                    }
                                                       );
                    var sendAsDomain = "true".Equals(config["SendAsDomain"], StringComparison.OrdinalIgnoreCase);
                    await relay.RelayAsync(email, target, domain, sendAsDomain, cancellationToken);
                }

                return(new OkResult());
            }
            catch (Exception e)
            {
                log.LogCritical(e, "Failed to process request!");
                return(new BadRequestResult());
            }
        }