How to add an attachment to a loaded MimeMessage (MimeKit) [duplicate] - c#

This question already has answers here:
MimeKit add attachments to a message loaded from mht file
(2 answers)
Closed last month.
Is there any general way to add an attachment to a mail read from an stream using MimeKit?
I need something like this
var message = MimeMessage.Load(inputStream);
var newMessage = AddSomeInfoAttachment(message);
newMessage.WriteTo(outputStream)
The part in question is "AddSomeInfoAttachment(message)". The attachment (for now) is just a text file (a string in fact).
It appears to be easy if you create a new message (http://www.mimekit.net/docs/html/Creating-Messages.htm) but I suspect that it's way more complicated to start with an already created one (for instance: Where in the MIME tree is supposed to go the attachment? Do I have to copy all other parts to a newMessage or can I just modify the original message in place?)
So far the only "Attachments" collections (with an Add) I see is using a BodyBuilder and I suspect that is not that easy with an already loaded MimeMessage.

In the most common scenario, the following code snippet should do what you want/expect:
var message = MimeMessage.Load(fileName);
var attachment = new TextPart("plain") {
FileName = "attachment.txt",
ContentTransferEncoding = ContentEncoding.Base64,
Text = attachmentText
};
if (!(message.Body is Multipart multipart &&
multipart.ContentType.Matches("multipart", "mixed"))) {
// The top-level MIME part is not a multipart/mixed.
//
// Attachments are typically added to a multipart/mixed
// container which tends to be the top-level MIME part
// of the message (unless it is signed or encrypted).
//
// If the message is signed or encrypted, though, we do
// do not want to mess with the structure, so the correct
// thing to do there is to encapsulate the top-level part
// in a multipart/mixed just like we are going to do anyway.
multipart = new Multipart("mixed");
// Replace the message body with the multipart/mixed and
// add the old message body to it.
multipart.Add(message.Body);
message.Body = multipart;
}
// Add the attachment.
multipart.Add(attachment);
// Save the message back out to disk.
message.WriteTo(newFileName);

Related

Download .eml file with Microsoft Graph C#

I have some problem with Microsoft Graph.I would like to download the attachments present in a specific email. I have verified that the type of object returned after this:
var attachments = graphClient.Me.Messages[msg.Id].Attachments.Request().GetAsync().Result;
foreach(var item in attachments) {
var current_attachment = graphClient.Me.Messages[msg.Id].Attachments[item.Id].Request().GetAsync().Result;
}
is an object of type Attachment.
Now, I would like to download this object (current_attachment) but I saw that the property ContentBytes isn't available.
I have tried to cast the object to FileAttachment, but it throw an exception.
Thank you.
This should be fairly straightforward. Specifically:
https://learn.microsoft.com/en-us/graph/outlook-get-mime-message
Even though Outlook does not save messages in MIME format, there are
two ways you can get an Outlook message body in MIME format:
You can append a $value segment to a get-message operation on that
message. If the message is attached to an Outlook item or group post,
you can append a $value segment to a get-attachment operation on that
item or group post. In either case, your app must have the appropriate
permissions to access the Outlook item or group post in order to apply
the get-message or get-attachment operation.
You can then save the message body content in a .EML file and attach
the file to records in business systems, such as those for CRM, ERP,
and bug tracking.
Here is an example:
https://learn.microsoft.com/en-us/graph/api/message-get?view=graph-rest-1.0&tabs=csharp
Gets the MIME content of a message in the signed-in user's mailbox.
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var stream = await graphClient.Me.Messages["4aade2547798441eab5188a7a2436bc1"].Content
.Request()
.GetAsync();
You can write "stream" to a disk file like this:
string path = #"\my\path\myfile.eml";
using(FileStream outputFileStream = new FileStream(path, FileMode.Create))
{
stream.CopyTo(outputFileStream);
}
The resulting .eml file will be the complete email, including all attachments.
You can do a similar call to get an InputStream for the ItemAttachment as you would do to get the InputStream for a Message.
See code below in java but will be similar for c#. The java API is missing the .content() option on Attachments but you can build the url and append $value instead.
URL requestUrl = graphClient.users("user#***.com").messages("*****").attachments("****").buildRequest().getRequestUrl();
InputStream is = new FileAttachmentStreamRequestBuilder(requestUrl.toString() + "/$value", graphClient, null).buildRequest().get();
// save the file
Files.copy(is, Paths.get(fileName + extension), StandardCopyOption.REPLACE_EXISTING);

determine if a message was sent or closed outlook

in c # I create a message m before sending it I show the user who can edit it and send or close it. How can I track the user closed this message or sent.
OutLookRef.Application oApp;
oApp = new OutLookRef.Application();
OutLookRef.MailItem mail = oApp.CreateItem(OutLookRef.OlItemType.olMailItem);
var pInspector = mail.GetInspector;
mail.Recipients.Add(address);
mail.Subject = subject;
mail.HTMLBody = body;
mail.Display();
All I got was to pause the code while this window is open
while (pInspector.CurrentItem is OutLookRef.MailItem)
{
System.Threading.Thread.Sleep(500);
}
also after sending, I would like to save this message to a disk, let's say mail.msg
It seems you are interested in the following properties:
MailItem.SendUsingAccount returns an Account object that represents the account under which the MailItem is to be sent.
MailItem.SentOnBehalfOfName returns a string indicating the display name for the intended sender of the mail message.
Namespace.CurrentUser returns the display name of the currently logged-on user as a Recipient object.
also after sending, I would like to save this message to a disk, let's say mail.msg
You may hook up to the ItemAdd event of the Items class which belongs to the Sent Items folder where you can save the item on the disk. The MailItem.SaveAs method saves the Microsoft Outlook item to the specified path and in the format of the specified file type. If the file type is not specified, the MSG format (.msg) is used.

In EWS, how to get message's both plain-text and HTML bodies as strings keeping the original character encoding

I'm working with Exchange 2010 (not Exchange 2013 which lets the caller request both plain-text and HTML bodies directly).
To get HTML body, I'm using something like:
ExtendedPropertyDefinition PR_BODY_HTML = new ExtendedPropertyDefinition(0x1013, MapiPropertyType.Binary);
ExtendedPropertyDefinition PR_INTERNET_CPID = new ExtendedPropertyDefinition(0x3FDE, MapiPropertyType.Long);
PropertySet properties = new PropertySet(BasePropertySet.FirstClassProperties);
properties.RequestedBodyType = BodyType.Text;
properties.Add(EmailMessageSchema.Body);
properties.Add(PR_BODY_HTML);
properties.Add(PR_INTERNET_CPID);
...
byte[] htmlBodyBytes;
string htmlBody;
int iCP;
if (item.TryGetProperty<int>(PR_INTERNET_CPID, out iCP))
{
// The code never enters here
}
if (item.TryGetProperty<byte[]>(PR_BODY_HTML, out htmlBodyBytes))
{
htmlBody = Encoding.GetEncoding(65001).GetString(htmlBodyBytes);
}
string textBody = item.Body.Text;
For plain-text body, I get the correct string representation. But HTML body gives me just bytes and I don't know the codepage to pass to GetString. Currently, UTF-8's codepage is hardcoded but this won't work for production. I need to either find out the codepage of the HTML part or find another method of extracting it from the message. Of course, I could make a separate query to EWS setting RequestedBodyType = BodyType.HTML but I would better not make an additional query. I thought PR_INTERNET_CPID MAPI property (0x3FDE) will fit my needs but it's never populated (I double-checked that it exists on the mail server but I can't get it via EWS).
So I need to either convince Managed EWS library to return both HTML and plain-text as strings or get me PR_INTERNET_CPID value. What can I do for that?
OK, it turns out that PidTagInternetCodepage (PR_INTERNET_CPID) has type MapiPropertyType.Integer, not MapiPropertyType.Long (although MSDN says PT_LONG). After the adjustment, I can get the value in question just fine.

c# open pop - save e-mail (HTML with inline attachements) to database

Found a problem with saving e-mail to database(as byte[] - already tried with various methods:
saving "RawMessage",
executing Message.
Load via "MemoryStream" etc..),
retrieving it and re sending.
When I send this saved e-mail, recipient does not see inline attached image (in place where image should be is information that picture was not found or couldn't be loaded).
My actual code version:
byte[] toDB = message.RawMessage; // then it goes to DB
//later in code
OpenPop.Mime.Message raw = new OpenPop.Mime.Message(fromDB, true);
//then I fill in new Message object with new values, only body remains the same:
mailMessage.Body = System.Text.Encoding.Default.GetString(raw.FindFirstHtmlVersion().Body);
Thanks :)

Generate HTML file at runtime and send as email attachment

I have a project requirement that we need to attach an HTML formatted log sheet to an email that gets sent to a user. I don't want the log sheet to be part of the body. I'd rather not use HTMLTextWriter or StringBuilder because the log sheet is quite complex.
Is there another method that I'm not mentioning or a tool that would make this easier?
Note: I've worked with the MailDefinition class and created a template but I haven't found a way to make this an attachment if that's even possible.
Since you're using WebForms, I would recommend rendering your log sheet in a Control as a string, and then attaching that to a MailMessage.
The rendering part would look a bit like this:
public static string GetRenderedHtml(this Control control)
{
StringBuilder sbHtml = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(sbHtml))
using (HtmlTextWriter textWriter = new HtmlTextWriter(stringWriter))
{
control.RenderControl(textWriter);
}
return sbHtml.ToString();
}
If you have editable controls (TextBox, DropDownList, etc), you'll need to replace them with Labels or Literals before calling GetRenderedHtml(). See this blog post for a complete example.
Here's the MSDN example for attachments:
// Specify the file to be attached and sent.
// This example assumes that a file named Data.xls exists in the
// current working directory.
string file = "data.xls";
// Create a message and set up the recipients.
MailMessage message = new MailMessage(
"jane#contoso.com",
"ben#contoso.com",
"Quarterly data report.",
"See the attached spreadsheet.");
// Create the file attachment for this e-mail message.
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
// Add time stamp information for the file.
ContentDisposition disposition = data.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(file);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(file);
disposition.ReadDate = System.IO.File.GetLastAccessTime(file);
// Add the file attachment to this e-mail message.
message.Attachments.Add(data);
You can use Razor for email templates. RazorEngine or MvcMailer might do the job for you
Use Razor views as email templates inside a Web Forms app
Razor views as email templates
http://www.codeproject.com/Articles/145629/Announcing-MvcMailer-Send-Emails-Using-ASP-NET-MVC
http://kazimanzurrashid.com/posts/use-razor-for-email-template-outside-asp-dot-net-mvc

Categories

Resources