Example of creating a draft with an attachment in C#? - c#

I've written a test application in C# that creates a draft message using the new Gmail API. It works fine when the message has no attachment.
I'm moving from the IMAP API and have used the MailBee.NET components with that API. The MailBee.NET components includes a class that produces an RFC 2822 message, so I've re-used this and have Base64-encoded the message and have assigned to the "Raw" property as described here:
https://developers.google.com/gmail/api/guides/drafts
MailMessage msg = new MailMessage();
msg.Subject = "test!";
msg.BodyPlainText = "Test content";
msg.Attachments.Add(#"D:\Trace.log", "Trace.log", Guid.NewGuid().ToString(), null, null, NewAttachmentOptions.Inline, MailTransferEncoding.Base64);
Message m = new Message();
m.Raw = Convert.ToBase64String(msg.GetMessageRawData());
Draft d = new Draft();
d.Message = m;
d = gs.Users.Drafts.Create(d, "me").Execute();
It works fine when no attachment is added, but fails with a 500 response when one is added:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "backendError",
"message": "Backend Error"
}
],
"code": 500,
"message": "Backend Error"
}
}
Could somebody please provide an example of how to do this using the .NET API? The example on the API page is very barebones and doesn't really give much in the way of useful information and the documentation isn't great. It would probably be best to use the Message / MessagePart / MessagePartBody classes included with the .NET Client, however I can't find any clear guidance or examples on their use so don't know where to begin.
Questions:
1) Can anybody provide some example code of creating a draft message with an attachment using the classes within the .NET Client?
2) Is it possible to attach more than one file? The documentation refers to a single file throughout and the Multipart guidance refers to exactly two parts: metadata and attachment.

Providing a sample "raw" field that you're uploading would definitely be helpful to debug (either base64 encoded or just directly).
However this sounds related to:
GMail API : unable to add an attachment in a draft

also about this:
m.Raw = Convert.ToBase64String(msg.GetMessageRawData());
you want to make sure you're using "web safe" (aka "url safe") base64 encoding alphabet from https://www.rfc-editor.org/rfc/rfc4648#section-5
as it says in the docs at the URL you mentioned:
"""
Your application can create drafts using the drafts.create method. The general process is to:
Create a MIME message that complies with RFC 2822.
Convert the message to a URL-safe base64-encoded string.
Create a draft, setting the value of the drafts.message.raw field to the encoded string.
"""
Google APIs use the

Much like for the poster of the other question GmailGuy referred to, this has magically started working overnight. So it must've been a Gmail-side problem after all.
Regarding:
m.Raw = Convert.ToBase64String(msg.GetMessageRawData());
Thanks for the heads-up on this; I had actually encoded it previously but while trying 20 different things to get things working I removed it and forgot to add it back in!
Also, to confirm: yes, you're able to add more than one attachment when you use the raw message approach.

Related

How to send an email in EWS/C# with Suppress Auto Responses?

I've been trying to find an answer to this within MSDN documentation and various other resources, but am unable to find something that works.
Here is some C# code I am using:
private ExtendedPropertyDefinition SurpressAutoResponse = new ExtendedPropertyDefinition(
DefaultExtendedPropertySet.InternetHeaders,
"X-Auto-Response-Suppress",
MapiPropertyType.String); // Also tried with StringArray and Integer
private ExtendedPropertyDefinition OtherID = new ExtendedPropertyDefinition(
DefaultExtendedPropertySet.InternetHeaders,
"X-Custom-ID-Property-Example",
MapiPropertyType.String);
{ some other code that's unimportant in between }
var mm = new EmailMessage(Global.Exchange);
mm.ToRecipients.Add("me#me.com"); // example address, of course
mm.Subject = Subject.Replace('\r', ' ').Replace('\n', ' ');
mm.SetExtendedProperty(SurpressAutoResponse, "OOF, NDR"); // Also tried {"OOF", "NDR"} and -1
mm.SetExtendedProperty(OtherId, "12345-1");
mm.Body = "Hello World";
mm.Send();
When I inspect the headers for the incoming email, I see that my "OtherId" is correctly set, but the X-Auto-Response-Suppress is not set. Any ideas how I should be getting exchange to suppress these out of office and delivery failure reports?
Notes:
I am targeting an Exchange 2010_SP2 server, which should support this
References:
https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcmail/ced68690-498a-4567-9d14-5c01f974d8b1
https://learn.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633654(v=exchg.80)
UPDATE
I decided to try testing the behavior of the email and set an auto-reply/OOF on my email account. Even though the properties of the email do not include the X-Auto-Response-Suppress header, I noticed that it indeed prevented a reply. My presumption is that the header is read on the Exchange server, which also probably processes the auto-responses instead of the client. Since the client doesn't act upon the header itself, Exchange saves some data by removing it from the original email before it's transferred. Can anyone who knows please confirm this is correct?
I have had issues using that header before as the MSDN is very vague on what all it actually does. And it is mostly only utilized by exchange servers and OOF purposes. Instead there are other headers that work better. Here is an article explaining why I think it would serve you well to use other headers. https://www.jitbit.com/maxblog/18-detecting-outlook-autoreplyout-of-office-emails-and-x-auto-response-suppress-header/
If you are only wanting to catch OOF then you can change the header to:
X-Auto-Response-Suppress:OOF
But I don't see that as a good example. Here is another thread on why this isn't always the best header to use: Detecting Outlook autoreply/out-of-office emails

C# MailKit HTML email received as plain text

I have a complex email template that contains many div, section and other HTML elements. The HTML template has reference to CSS(uploaded to server). I am using the below code to send HTML email via MailKit :
var message = new MimeMessage();
var bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody = File.ReadAllText(pathToHtmlFIle);
message.Body = bodyBuilder.ToMessageBody();
client.Send(message);
But the client only receives everything in plain-text, no colors, no formatting. Is this the expected result ?
I think you need to use either inline CSS or CSS embedded in the head section. Since most webmail clients block links to external stylesheets, it is rare to see this method employed in an email.
After struggling a lot with this topic, I finally figure out the error was the double quotes inside the html...Use notepad++ to replace (quick launched with ctrl+f) all " for '. Holy remedy, after only receiving plain/text I finally received the text/html.
PD: Do not use bootstrap nor try to link an external source 'cause mail clients block external css providers. Use strictly style attributes for all tags.

EWS Managed API 2.0 message encoding

I have a question bout the encoding of email messages when sending via EWS Managed API 2.
I haven't been able to find any clear answer to this on the MSDN pages so I'll try you guys.
When using the standard .NET SmtpClient I can set the encoding of both the body and the subject attribute (I need utf-8) - this doesn't seem to be the case when using EWS Managed API 2.
Or, is it in fact the MimeContent attribute of the EmailMessage that is used for this and if so, how do I do the same thing for the subject of the email message?
For the body - is this the correct way to do it?
EmailMessage.MimeContent =
new MimeContent("utf-8", Encoding.UTF8.GetBytes("<body text html or plain text>"));
And then I don't set the EmailMessage.Body attribute or?
Never mind, it appears that I don't have the specify utf-8. I have now tried to set the body attribute with both text and HTML that included special characters and in both cases the result looked correct in the mail.
EmailMessage.Body = new MessageBody(BodyType.HTML, "<html content>");
EmailMessage.Body = new MessageBody(BodyType.Text, "plain text content>");

Link formatting not working

On the Slack website, I can format a message like this:
{
"text": "<http://google.com|link to google>"
}
And in the message it will appear like this:
link to google
But I am trying to write a bot and those links aren't working. Using my websocket connection I can send a message like this:
var send = new MessageToSlack()
{
type = "message",
channel = msg.channel,
text = $"http://google.com"
};
ws.SendAsync(JsonConvert.SerializeObject(send), b => { });
And Slack will correctly interpret http://google.com as a link and display it like:
http://google.com
But if I try to send a message with the link in angle brackets with the pipe between the link and the link text (which works on Slack's site) like this:
var send = new MessageToSlack()
{
type = "message",
channel = msg.channel,
text = $"<http://google.com|to google>"
};
ws.SendAsync(JsonConvert.SerializeObject(send), b => { });
I end up with:
<http://google.com|to google>
So how do I get this working from my bot? Why is it not able to parse by links correctly? What am I missing?
As far as I can see from the docs, this should work. Here in the section on formatting messages it says:
The RTM API only supports posting simple messages formatted using our default message formatting mode.
And links to here which does mention links with the pipe character, so I think it should work.
(note MessageToSlack is just an ordinary .NET class with type, channel and text properties that gets serialized by JSON.Net and appears to give the correct JSON. ws is my websocket connection from the WebSocketSharp nuget package)
JSON:
{
"id": 1,
"type": "message",
"channel": "C6QRKT0EA",
"text": "<http://google.com|to google>"
}
Edit: So it seems if I switch from replying with the web socket connection and instead post to https://slack.com/api/chat.postMessage, it will work correctly, but it's a bit more fiddly to use and the documentation led me to believe that the links should work without needing to jump through that particular hoop. Am I just misreading the docs? Or are docs just not very clear on this point?
Try to enable markdown support by adding "mrkdwn": true to your json
{
"type": "message",
"channel": "C6QRKT0EA",
"text": "<http://google.com|to google>",
"mrkdwn": true
}
Read Message Formatting section. Hope it will help.

Mimekit/mailkit download message body?

I have been making my own mail client recently and added a receive option, I used mimekit and mailkit as plugins and was able to download most of my mails with a reader that is supposed to show content(right now it shows subject, to, from, date)
The way I downloaded the subject, to, ... is msg.envelope.subject, msg.envelope.to
But I cannot download the body like this :( when doing either msg.body, msg.textbody, msg.bodyparts, ... they all result in NOTHING, the place where it should be is just empty, I can't get it downloaded :(
Can anyone help me?
There are 2 ways to get the message body:
1. Download the Whole Message
This method is probably the easiest way.
To do this, all you need to do is call:
var message = folder.GetMessage (uid);
or
var message = folder.GetMessage (index);
I would recommend always using the UniqueId of the message. Since you are already using the Fetch method, all you need to do to make sure that you have the UniqueId of the message is to include the MessageSummaryItems.UniqueId in your fetch request:
var messages = folder.Fetch (0, -1, MessageSummaryItems.UniqueId |
MessageSummaryItems.Envelope | ...);
Once you have the message, you can do whatever you want with it.
For rendering the message, I would recommend taking a look at the MessageReader sample included in the MimeKit GitHub repository.
It will show you how to properly render a MimeMessage.
2. Download Only What You Need
This method is a bit harder but can be more efficient as far as network bandwidth usage goes.
The first thing you need to do is to make sure to include the MessageSummaryItems.BodyStructure bit flag in the Fetch method. For example:
var messages = folder.Fetch (0, -1, MessageSummaryItems.Envelope |
MessageSummaryItems.BodyStructure);
(You'll probably want other fields, but that's just an example to show you how to bitwise-or flags together to request multiple message summary items).
By requesting the BodyStructure of the messages, you'll be able to make use of the msg.Body property.
Each msg.Body will be a BodyPart object which is an abstract class. The 2 main subclasses are BodyPartMultipart and BodyPartBasic. You can use the as cast or the is keyword to figure out which one it is:
var multipart = msg.Body as BodyPartMultipart;
if (multipart != null) {
// the top-level body part is a multi-part
} else {
// the body is a basic singleton part
}
This is how you would iterate over the subparts of a BodyPartMultipart:
foreach (var part in multipart.BodyParts) {
// each part will either be a BodyPartMultipart
// or a BodyPartBasic, just like before...
}
There are also 2 subclasses of BodyPartBasic which are: BodyPartText and BodyPartMessage. A BodyPartText is a textual-based MIME part (meaning it has a MIME-type of text/*) whereas a BodyPartMessage is an embedded message (and will have a MIME-type of message/rfc822).
Since MIME is recursive, you'll need to implement a recursive function to walk the MIME tree structure to find whatever MIME part you are looking for.
For your convenience, the TextBody and HtmlBody properties on the IMessageSummary interface will locate and return the text/plain and text/html body parts, respectively.
It should be noted, however, that these properties only work in cases where the structure of the message follows the standard convention (notice I said convention, there is no formal standard dictating the location of the message text within a MIME hierarchy).
It should also be noted that if your mail client will be rendering the HTML body, the HTML body part may be part of a group of related MIME parts (i.e. a child of a multipart/related), but the HtmlBody property will not be able to return that and so implementing your own recursive logic will be a better option.
For an example of how to do this, check out the ImapClientDemo sample in the MailKit GitHub repository. The logic currently resides in the MainWindow.cs code.

Categories

Resources