1
votes

Try to automate a process here - we have a system that generated batch SMTP files dumps them to a folder - a 3rd party .net component reads the file and then sends it along to our SMTP server. Problem is this component create and destroys a new smtp connection with every email. So painfully slow - I checked with the vendor and no plans to do it any other way ..ever.. So wanted to spin up my own simple service - the feeding application creates batch smtp files.. I try to load this via MimeKit and get an parsing error - which i get not really a normal MIME a client would use.. is there any option to get MimeKit or even MailKit to load and relay this mail?

Simplified format of the file.. all the data is muged up for clarity - I guess I could strip out the smtp command and set them in the code and just stream in the actual MIM portion - but seems there should be a simpler way


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
1

1 Answers

0
votes

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

That's what you'll have to do. There's no other way to do it. Keep in mind that you'll also want to strip out the line that is just . and the QUIT line as well.

The file format you've got is essentially an "SMTP command script" which includes embedded MIME, but isn't MIME itself and so MimeKit/MailKit's parser cannot handle it.

There's no real need to keep the SMTP commands that you strip out because MailKit's SmtpClient doesn't allow you to send commands since it handles sending them itself.

MailKit auto-detects the addresses it needs to send from/to based on the Sender/From and To/Cc/Bcc headers, but I suppose that it might be worth parsing the MAILFROM: and RCPT TO: commands in order to get an explicit list.

Something like this:

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);
}

The hardest part will be to process the batch smtp files efficiently. You could use a StreamReader to read line-by-line, processing input until you've read a DATA line (everything following that is part of the message right up until you encounter a line matching .), but the problem with that is then you'd need to continue using the StreamReader to read data and dump it into a MemoryStream or something that you could then parse using MimeMessage.Load() (PS: don't forget to rewind the stream before parsing it).

A better option if you have the skills to do it would be to implement a custom IMimeFilter and then use MimeMessage.Load() with a FilteredStream that filters the source stream through your custom filter.

For some sample filter implementations, take a look at https://github.com/jstedfast/MimeKit/tree/master/MimeKit/IO/Filters

The easiest ones to understand might be the Unix2Dos and Dos2Unix filters.

Another thing to keep in mind is that as you are filtering the "MIME" portion of the content in those batch files, you will need to unmunge lines that start with two dots (..) by removing the first dot (.).

The Pop3Stream code in MailKit has to do this process as well since POP3 munges MIME lines beginning with a . by prepending an extra ..

You can see that code here: https://github.com/jstedfast/MailKit/blob/master/MailKit/Net/Pop3/Pop3Stream.cs#L344

(Unfortunately, it is pretty complex logic because it deals with buffering as well).

Then, once you've stripped out all of the lines with SMTP commands and processed them with the above code snippet, you can send via MailKit's SmtpClient using the following logic:

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);
}