Mail

Send, Receive, and Utilities

Send transmits the composed message through the configured SMTP server and throws when it cannot deliver, so a run that continues is a run that sent. Receive reads from whichever incoming server is configured, IMAP or POP3. WithUnreadOnly limits it to the messages the server still has as unread, and WithMaxMessages caps how many one Receive fetches, taking the newest first. Both default to every message, which is what Receive has always done and, on a mailbox of any size, a great deal of downloading. The overload taking an out List<ReceivedEmail> hands the messages back in the same call. Each ReceivedEmail carries Subject, From, Body, HtmlBody, Received, MessageId, and Attachments, the filename of everything that came with it. Body is the plain text part and falls back to the html when the sender wrote no text part at all, which is common for transactional mail. Received is when the message was sent, in local time, and MessageId is how the same message is recognised across runs. SaveTo writes the attachments of every received message into a directory, creating it when it is not there, and ReceivedEmail.SaveTo does the same for one message, handing back a GPALFile for each file written. Once a message has been dealt with, MarkAsRead and Delete on the ReceivedEmail act on that one, and MarkAllAsRead and DeleteAll on the mail object act on everything Receive collected, in a single connection. Delete flags and expunges, so the message is gone rather than left flagged. Clear resets the envelope, to, cc, bcc, subject, body, and attachments, while keeping the server settings and the from address, since that is who you send as. ParseEmailAddresses is a static utility that parses a comma-separated string of addresses into a List<MailboxAddress>.

NOTE

Marking or deleting as part of the fetch would consume mail a run never got to if it failed half way through. Call MarkAsRead once the workflow has finished with the message, so a failed run finds it unread and waiting next time. DeleteAll acts on what Receive collected rather than on the mailbox, so with a filter in front of it, it empties only what the workflow read.

WARNING

POP has no notion of a read message, so WithUnreadOnly warns and fetches everything anyway, and marking and deleting need the IMAP identity a POP message does not carry. WithMaxMessages still applies. Use IMAP for any workflow that has to consume mail rather than only read it.

Examples

GPAL Fluent: High-level fluent C# API

//Receive fills the message list and returns the mail object, so SaveTo and MarkAllAsRead can follow it in the same chain when the whole batch is treated alike. Per-message MarkAsRead and Delete open a connection each, so a loop over many messages is many logins; the MarkAllAsRead and DeleteAll pair do the same work in one. An attachment is written under the filename the sender chose, reduced to a filename first, so a name like ..\..\startup.cmd cannot write outside the directory you asked for. A file already in that directory is replaced.

// the mail object first, then the server settings and the envelope on it

IGPALMail mail = GPAL.Mail.ToGPALObject();


// Only what has not been read, and never more than 25 at a time

IGPALMail mail = mail

.WithIMAPServerName("imap.example.com")

.WithCredentials(mailLogin)

.WithUnreadOnly(true)

.WithMaxMessages(25)

.ToGPALObject();


mail.Receive(out List<ReceivedEmail> received);


// Handle each one, and only then say it has been handled

foreach (ReceivedEmail email in received)

{

if (false == email.Subject.Contains("Invoice")) continue;


List<GPALFile> saved = email.SaveTo((GPALFile)"C:\Inbox\invoices");


foreach (GPALFile invoice in saved)

GPAL.PublishSimpleEvent(GPALEventType.NOTICE,

$"Saved [{invoice.Filename}] from [{email.From}] sent [{email.Received}]");


email.MarkAsRead();

}


// Or take the lot and finish with it in one connection

mail.Receive(out received)

.SaveTo((GPALFile)"C:\Inbox\attachments")

.MarkAllAsRead();

💬 Ask GPAL