How to extract attachment from application/pkcs7-mime received from Microsoft Graph API in .NET Core - microsoft-graph-api

I am downloading attachments with Microsoft Graph API in .NET Core 3.1.
await client.Users[mail.OwnerEmail].Messages[mail.Id].Attachments.Request().GetAsync()
Recently one email had strange attachment with content type application/pkcs7-mime (extension .p7m). I need to extract attachments inside this signed attachment. Outlook shows 2 attachments for this mail: pdf and xml. I need these 2 files.
I found this thread, but I don't understand the answer.
I tried:
var signed = new SignedCms();
signed.Decode(signedAttachment.Content); //Exception: ASN1 corrupted data.
and
new SignedCms(new ContentInfo(signedAttachment.Content))
and receive some friendly name and version:
but I don't know how to extract attachments.
Edited:
Also tried:
var envelopedCms = new EnvelopedCms();
envelopedCms.Decode(signedAttachment.Content);
and Decrypt ... Nothing.

Related

How to get the shared file with Microsoft Graph?

I want to share files from MS OneDrive to a user via MS graph API. And user can view my shared file directly through the link. I have read the Document of Creating a sharing Link for a DriveItem and use this API to create a sharing link for my sharing files.
I wonder how to implement with MS graph API? Any suggestion and tips are welcome. Thanks
According to your description, I assume you want to get the share file by using MS Graph API.
Base on my test, We can create a shareLink for this this file.
Then we can use the following steps to get the file information by converting the shareLink.
Encoding the shareLink by using the following logic:
1)First, use base64 encode the URL.
2)Convert the base64 encoded result to unpadded base64url format by removing = characters from the end of the value, replacing / with _ and + with -.)
3)Append u! to be beginning of the string.
If you want access the shared files, you can use the following API:
GET /shares/{shareIdOrUrl}/driveItem
The shareIdOrUrl parameter is the result in step1.
This API will return all the information about the shared file.
As an example, to encode a URL in C#:
string sharingUrl = "https://onedrive.live.com/redir?resid=1231244193912!12&authKey=1201919!12921!1";
string base64Value = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(sharingUrl));
string encodedUrl = "u!" + base64Value.TrimEnd('=').Replace('/','_').Replace('+','-');
For more detail, we can refer to this document.

Create inline image that displays properly in iOS mail app

So I have tried 2 different approaches to creating an inline image using c#:
Using an AlternateView
Using an inline Attachement
Option 2 is worse in that it does not appear inline on any of my test clients (outlook 2010/2013, Samsung android email client, ios 10 email client).
Option 1 is almost perfect, all clients display the inline image correctly as long as there are no other attachments. However, if you add a file attachment to the email, only on the iOS email app you get a strange side effect. On iOS, the client displays both the inline image and the attachment as attachments (the inline image is shown as an icon).
I have tried to figure this out by composing an email in Outlook with an embedded image and an attachment. Outlook generates what looks to be two regular attachments (looking at the raw message data from both Outlook and dotNet generated emails), with the image being marked as content-disposition inline. And this works on all my test clients. Except when using the .Net Mail message api to replicate this (option 2), it doesn't work. I am at a loss to understand what is going on here.
Edit 1
What's interesting is that when using Option 2, the email body is delivered encoded as base64. This is different than how the Outlook client manages to do it. There the body is in plain text and the inline attachment image is the only thing encoded in bas64.
Edit 2
Setting the following properties when using Option 2 returns the body to being plain text again:
mail.BodyEncoding = Encoding.UTF8;
mail.BodyTransferEncoding = TransferEncoding.QuotedPrintable;
So to get this to work I had to combine both approaches. Below is what worked for me, it displays the signature image as intended (inline/embedded) image and the attachment as an icon (in iOS anyway). This also displayed correctly on a Samsung Android phone and in outlook 2010/2013. For the sake of simplicity, I will only include the embedded image in the mail body as an example:
var smtpMail = new SmtpClient
using (var mail = new MailMessage())
{
mail.From = new MailAddress(Settings.Default.FromAddress, Settings.Default.FromDisplayName);
mail.To.Add(toAddress);
mail.Subject = subjectText;
mail.IsBodyHtml = true;
mail.BodyEncoding = Encoding.UTF8;
mail.BodyTransferEncoding = TransferEncoding.QuotedPrintable;
mail.Attachments.Add(new Attachment(nonInlinefilePath));
var imgCid = "img001.jpg"
var bodyText = $"<html><body><img src=\"cid:{imgCid}\" alt=\"Sample Image\" /></body></html>";
var altView = AlternateView.CreateAlternateViewFromString(bodyText, Encoding.UTF8, MediaTypeNames.Text.Html);
var inlineFileResource = new LinkedResource(imagePath, MediaTypeNames.Image.Jpeg)
{
TransferEncoding = TransferEncoding.Base64,
ContentId = imgCid,
ContentType =
{
Name = imgCid
},
};
var inlineFileAttachment = new Attachment(imagePath, MediaTypeNames.Image.Jpeg)
{
ContentId = imgCid
};
inlineFileAttachment.ContentDisposition.Inline = true;
inlineFileAttachment.ContentDisposition.DispositionType = DispositionTypeNames.Inline;
altView.LinkedResources.Add(inlineFileResource);
mail.AlternateViews.Add(altView);
mail.Attachments.Add(inlineFileAttachment);
smtpMail.Send(mail);
}
I don't know enough about either email protocols or the iOS email app to know why this is necessary, but after many, many, many different attempts to get iOS mail app to display this properly, this combo was the only one that worked.
I had a similar issue with a work project. Images embedded in the message body using System.Net.Mail LinkedResource, would appear fine in most email clients, but not with iOS emails after a version upgrade during version 10.
The images would have zero bytes and added attachments with zero size. What I did was to fix this was to define the media type, whereas before I didn't.
Before:
LinkedResource logo = new LinkedResource(HttpContext.Current.Server.MapPath("/images/imgname.png"));
After:
LinkedResource(HttpContext.Current.Server.MapPath("/images/imgname.png"), "image/png");
as a possible alternative you could try base64 encoding your image.
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAADSCAMAAABThmYtAAAAXVB" alt="img" />
I just tested my image in Outlook, outlook for web, and iOS Mail. worked in all for me.
you could use this tool (or any base64 encoder) to generate a base64 image tag
more info here.
another good source of info on this subject

Azure blob authorization header

I am trying to use refit to upload to azure blob storage from a Xamarin iOS application. This is the interface configuration I am using for Refit:
[Headers("x-ms-blob-type: BlockBlob")]
[Put("/{fileName}")]
Task<bool> UploadAsync([Body]byte[] content, string sasTokenKey,
[Header("Content-Type")] string contentType);
Where the sasTokenKey parameter looks like this:
"/content-default/1635839001660743375-66f93195-e923-4c8b-a3f1-5f3f9ba9dd32.jpeg?sv=2015-04-05&sr=b&sig=Up26vDxQikFqo%2FDQjRB08YtmK418rZfKx1IHbYKAjIE%3D&se=2015-11-23T18:59:26Z&sp=w"
This is how I am using Refit to call the azure blob server:
var myRefitApi = RestService.For<IMyRefitAPI>("https://myaccount.blob.core.windows.net");
myRefitApi.UploadAsync(photoBytes, sasTokenKey, "image/jpeg"
However I am getting the follow error:
Response status code does not indicate success: 403 (Server failed to
authenticate the request. Make sure the value of Authorization header is
formed correctly including the signature.)
The SAS url is working fine if I call it directly like this
var content = new StreamContent(stream);
content.Headers.Add("Content-Type", "jpeg");
content.Headers.Add("x-ms-blob-type", "BlockBlob");
var task = HttpClient.PutAsync(new Uri(sasTokenUrl), content);
task.Wait();
So basically I am just trying to do the same thing using Refit.
Any idea how to get Refit working with Azure Blob Storage?
Thanks!
[UPDATE] I am now able to upload the bytes to the azure blob server but something seems to be wrong with the byte data because I am not able to view the image. Here is the code I am using to convert to byte array.
byte[] bytes;
using (var ms = new MemoryStream())
{
stream.Position = 0;
stream.CopyTo(ms);
ms.Position = 0;
bytes = ms.ToArray();
}
[UPDATE] Got it fixed by using stream instead of byte array!
I see %2F and %3D and I'm curious if refit is encoding those a second time. Try sending the token without encoding it.
This is incorrect use of Authorization header. You use Authorization header when you want to authorize the requests using account key. If you have the Shared Access Signature then you really don't need this header as the authorization information is included in the SAS itself. You can simply use the SAS URL for uploading files.

uploading a file from iOS mobile application to SharePoint

I'm working on a SharePoint mobile solution where I'm using the web services exposed in server/_vti_bin/sitedata.asmx, server/_vti_bin/Lists.asmx and server/_vti_bin/copy.asmx.
I'm able to successfully fetch the list of sites, document libraries and files using the services defined in server/_vti_bin/sitedata.asmx.
Now I'm actually trying to upload an image file from Photo Albums available in iOS to SharePoint. For this, I tried using CopyIntoItems web service, where in I'm getting the following error response.
<CopyResult ErrorCode="DestinationInvalid" ErrorMessage="The Copy web service method must be called on the same domain that contains the destination url." DestinationUrl="http://xxxxserveripxxxxxx/Shared Documents/image1.png"/>
But came to know that this service is used only if the file to be uploaded is also from the same source(i.e., from sharepoint).
Is there any other way to upload a file available in iPhone to SharePoint.
Also tired addAttachment service defiend in server/_vti_bin/Lists.asmx but I'm unable to identify the input parameters which requires list name and list Item ID.
I'm trying to upload a file to Shared Documents, so I've List Name value which is the one in curly braces of Shared Documents but now what should be the List Item Id value?
These are the details I've with regard to "Shared Documents" document library.
{
AllowAnonymousAccess = false;
AnonymousViewListItems = false;
BaseTemplate = DocumentLibrary;
BaseType = DocumentLibrary;
DefaultViewUrl = "/Shared Documents/Forms/AllItems.aspx";
Description = "Share a document with the team by adding it to this document library.";
InheritedSecurity = true;
InternalName = "{425F837A-F110-4876-98DE-C92902446935}";
LastModified = "2013-07-26 20:09:58Z";
ReadSecurity = 1;
Title = "Shared Documents";
},
So, I'm using the using InternalName value for listName tag.
What should be the value of listItemID?
Am I going in the right way or is there any other approach to upload a local file from mobile to SharePoint?
Thanks
Sudheer
Are you actually calling a URL or are you using the IP (you x'ed it out and said server IP)? If you don't have Alternate Access Mappings defined for the IP, uploads will fail but the GET requests will generally work ok.

Reimporting an EML file through IMAP

I have a bunch of .eml files exported/archived using 'archivemail'. Now I need to restore
some the files completely on the IMAP server. Is there some simple tool taking an .eml/mail file with multiple emails and restoring it on an IMAP server
You can use Mail.dll .NET IMAP library for that:
using (Imap imap = new Imap())
{
imap.Connect("server"); // or ConnectSSL
imap.Login("user", "password");
string eml = File.ReadAllText("email.eml");
imap.UploadMessage("INBOX", eml);
imap.Close();
}
Mail.dll can also parse the .eml files if you need to implement some custom logic before uploading:
IMail email = new MailBuilder().CreateFromEml(eml);
Please note however that this is a commercial product I helped to develop.

Resources