Mimekit / MailKit BSMTP 文件

Mimekit / MailKit BSMTP Files

尝试在此处自动执行一个过程 - 我们有一个生成批处理 SMTP 文件并将其转储到文件夹的系统 - 第 3 方 .net 组件读取文件,然后将其发送到我们的 SMTP 服务器。问题是此组件会为每封电子邮件创建和销毁新的 smtp 连接。太慢了——我和供应商核实了一下,没有任何其他方式的计划……永远……所以想启动我自己的简单服务——馈送应用程序创建批处理 smtp 文件。我尝试通过 MimeKit 加载它和收到解析错误 - 我得到的不是客户端会使用的真正正常的 MIME.. 是否有任何选项可以让 MimeKit 甚至 MailKit 加载和中继此邮件?

文件的简化格式.. 为了清晰起见,所有数据都被弄乱了——我想我可以去掉 smtp 命令并将它们设置在代码中,然后只在实际的 MIM 部分中流式传输——但似乎应该有更简单的方法


PORT 25
HELO mydomain.com
MAIL FROM: <asdlfjasdfasdfadsf@mydomain.com>
RCPT TO: <foobar@blah.com>
DATA
From: <foobar@foo.com>
To: foovar@blah.com
Subject: Test
Date: Wed, 04 Nov 2020 11:31:52 -0600
Message-ID: <2asdfadfadaf9-0@v116.mydomain.com>
MIME-Version: 1.0
Content-Type: multipart/mixed;
    boundary="--=036c8f0f_0fd5_48a2_85b7_b5310c3b811b"

----=036c8f0f_0fd5_48a2_85b7_b5310c3b811b
Content-Type: multipart/alternative;
    boundary="--=6b227ff4_d132_4000_9af6_f92a291f8101"

----=6b227ff4_d132_4000_9af6_f92a291f8101
Content-Type: text/plain;charset="UTF-8"
Content-Transfer-Encoding: Quoted-Printable

some content here


----=6b227ff4_d132_4000_9af6_f92a291f8101
Content-Type: text/html;charset="UTF-8"
Content-Transfer-Encoding: Quoted-Printable

html content here

----=6b227ff4_d132_4000_9af6_f92a291f8101--

----=036c8f0f_0fd5_48a2_85b7_b5310c3b811b--
.
QUIT

I guess I could strip out the smtp command and set them in the code and just stream in the actual MIM portion

这就是你必须要做的。没有其他方法可以做到这一点。请记住,您还需要删除 . 行和 QUIT 行。

您获得的文件格式本质上是一种“SMTP 命令脚本”,其中包括 嵌入式 MIME,但不是 MIME 本身,因此 MimeKit/MailKit解析器无法处理它。

没有必要保留您删除的 SMTP 命令,因为 MailKit 的 SmtpClient 不允许您发送命令,因为它会自行处理发送命令。

MailKit auto-detects 它需要发送的地址 from/to 基于 Sender/From 和 To/Cc/Bcc headers,但我想这可能是值得的解析 MAILFROM:RCPT TO: 命令以获得显式列表。

像这样:

var recipients = new List<MailboxAddress> ();
MailboxAddress sender = null;
    
if (line.StartsWith ("MAIL FROM:", StringComparison.OrdinalIgnoreCase)) {
    var address = line.Substring ("MAIL FROM:".Length);
    if (MailboxAddress.TryParse (address, out var mailbox))
        sender = mailbox;
} else if (line.StartsWith ("RCPT TO:", StringComparison.OrdinalIgnoreCase)) {
    var address = line.Substring ("RCPT TO:".Length);
    if (MailboxAddress.TryParse (address, out var mailbox))
        recipients.Add (mailbox);
}

最难的部分是高效地处理批处理 smtp 文件。您可以使用 StreamReader 来读取 line-by-line,处理输入直到您读取 DATA 行(后面的所有内容都是消息的一部分,直到您遇到匹配 .), 但问题是你需要继续使用 StreamReader 来读取数据并将其转储到 MemoryStream 或你可以使用 [=21= 解析的东西](PS:不要忘记在解析之前倒带流)。

如果您有能力做到这一点,更好的选择是实施一个自定义 IMimeFilter and then use MimeMessage.Load() with a FilteredStream,通过您的自定义过滤器过滤源流。

对于一些示例过滤器实现,请查看 https://github.com/jstedfast/MimeKit/tree/master/MimeKit/IO/Filters

最容易理解的可能是 Unix2Dos 和 Dos2Unix 过滤器。

另一件要记住的事情是,当您过滤那些批处理文件中内容的“MIME”部分时,您将需要取消删除以两个点 (..) 开头的行,方法是删除第一个点 (.).

MailKit 中的 Pop3Stream 代码也必须执行此过程,因为 POP3 通过在前面附加一个额外的 ..

来修改以 . 开头的 MIME 行

您可以在此处查看该代码:https://github.com/jstedfast/MailKit/blob/master/MailKit/Net/Pop3/Pop3Stream.cs#L344

(不幸的是,它的逻辑相当复杂,因为它也处理缓冲)。

然后,一旦您使用 SMTP 命令删除所有行并使用上面的代码片段处理它们,您就可以使用以下逻辑通过 MailKit 的 SmtpClient 发送:

using (var client = new SmtpClient ()) {
    client.Connect (host, port, SecureSocketOptions.Auto);
    client.Authenticate (username, password);

    foreach (batchFile in batchFiles) {
        using (var stream = File.OpenRead (batchFile)) {
            var message = MyCustomParseMessage (stream, out MailbnoxAddress sender, out List<MailboxAddress> recipients);

            client.Send (message, sender, recipients);
        }
    }

    client.Disconnect (true);
}