I started using #jstedfast Mimekit/Mailkit library, which is great by the way, to pull undeliverables using its subject line for search. I tried using the message.to, message.resentto.
how do i get that information. My first try today. I was able to get the list and the body but I just need the email. I tried using s22.imap but there's no support anymore then I discovered this. I know you're active here #jstedfast I need you help..there's no discussion tab in your github.
Thanks in advance
If you look at the raw message source, does the value of the Content-Type header match something along the lines of multipart/report; report-type=delivery-status? If so, it is very likely that this message will have a sub-part with a Content-Type header with a value of message/delivery-status. It should be the second child part of the multipart/report (the first part should be a human-readable explanation).
If so, you can cast the message/delivery-status MimeEntity to an instance of a MessageDeliveryStatus. You'll notice that the MessageDeliveryStatus class has a property called StatusGroups which is a list of multiple collections of headers (e.g. a list of HeaderList objects).
Each HeaderList contains information about a particular recipient that failed. I think what you want to do is look at the Final-Recipient header which will contain 2 pieces of information:
The address-type (should typically be "rfc822")
The mailbox of the recipient (which is what you want)
Unfortunately, MimeKit does not have any tools to parse the Final-Recipient header, but it should be trivial to locate the end of the address-type parameter in the header value by using IndexOf (';') and then you can use something like MailboxAddress.TryParse() to parse it (or you could probably just Substring() the value w/o parsing).
So, the way this might look in code is this:
string[] GetUndeliverableAddresses (MimeMessage message)
{
var report = message.Body as MultipartReport;
if (report == null)
throw new ArgumentException ("This is not a multipart/report!");
MessageDeliveryStatus status = null;
for (int i = 0; i < report.Count; i++) {
status = report[i] as MessageDeliveryStatus;
if (status != null)
break;
}
if (status == null)
throw new ArgumentException ("Did not contain a message/delivery-status!");
var undeliverables = new List<string> ();
for (int i = 0; i < status.StatusGroups.Count; i++) {
var recipient = status.StatusGroups[i]["Final-Recipient"];
int semicolon = recipient.IndexOf (';');
var undeliverable = recipient.Substring (semicolon + 1).Trim ();
undeliverables.Add (undeliverable);
}
return undeliverables.ToArray ();
}
For more information on message/delivery-status, see https://www.rfc-editor.org/rfc/rfc3464
Hope that helps.
this is what I did
foreach (var uid in inbox.Search(query))
{
var message = inbox.GetMessage(uid);
// Console.WriteLine("Subject: {0}", message.Subject);
//Console.WriteLine("Subject: {0}", message.Headers);
// Console.WriteLine("Subject: {0}", message.BodyParts);
var text = message.BodyParts;
string src = text.ElementAt(1).ToString();
int srcStart = src.IndexOf("RFC822;",0); << i used final-recipient intially
int srcEnd = src.IndexOf("Action", 0);
Console.WriteLine("Email:" + src.Substring(srcStart + 8, srcEnd - (srcStart + 8)));
Console.WriteLine(src);
//foreach (var part in message.BodyParts)
//{
// Console.WriteLine(part);
// // do something
//}
}
let me know if there could be a problem..will I get the rfc822 if the recipient inbox is full? there's no way i can test that.. I tested with emails with nonexistent domain, mailbox does not exist..with live.com, randomdomain.com,yahoo.com and gmail. gmail, on the other hand does not return any undeliverables.
I am currently doing a API HTTP POST project.
I should be getting
"[{\"ID\":\"311d1977-4772-435a-92aa-028791c53154\",\"ParentID\":\"187a064e-ffea-45a2-9264-9acecff911e1\",\"Type\":\"txt\",\"OwnerID\":\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\",\"Name\":\"Davinshi.txt\",\"CreatedBy\":\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\",\"CreatedDate\":\"2015-06-05T04:11:33.187\",\"Status\":0,\"Mark\":null},{\"ID\":\"25c80f4e-679c-4093-ade9-0b99da480153\",\"ParentID\":\"187a064e-ffea-45a2-9264-9acecff911e1\",\"Type\":\"jpg\",\"OwnerID\":\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\",\"Name\":\"leonid afremov.jpg\",\"CreatedBy\":\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\",\"CreatedDate\":\"2015-06-05T04:11:46.61\",\"Status\":0,\"Mark\":null}
However with the follow code I am getting a weird output
using (var client = new WebClient())
{
var val = new NameValueCollection();
foreach (var item in values)
{
val.Add(item.Key, item.Value);
}
var response = client.UploadValues(url, val);
return Encoding.Default.GetString(response);
}
This is the output
\"[{\\\"ID\\\":\\\"311d1977-4772-435a-92aa-028791c53154\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Davinshi.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:33.187\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"25c80f4e-679c-4093-ade9-0b99da480153\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"leonid afremov.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:46.61\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"5648cc67-1408-4935-a656-0f9b5116db8d\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"misty mood leonid.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:49.437\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"7402e7b8-1ec4-4bf8-9042-142a69cecbcd\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"winter sparkle.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:12:03.26\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"7159e926-1601-41d6-8dce-20e5daab90a6\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"gentle rain beata sasik.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:40.6\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"e61f7bc4-bebf-403b-a478-22b36856a6df\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"MoonLight.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:50.797\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"e46e6250-655b-4105-a888-2574750f2944\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"blue fire.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:27.037\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"bfca703b-1720-4a67-b0a4-2f6146c820aa\\\",\\\"ParentID\\\":null,\\\"Type\\\":\\\"folder\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"School\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:17.96\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"5c1bf9ca-b368-46c8-9804-3254eda00806\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Woman.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:12:06.607\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"8ad07f3c-7a57-4add-92c0-329aca372c8b\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"intimacy worship.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:40.727\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"ac5384c4-66ca-45cd-99f0-437c0789a26a\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Under the Rain.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:12:01.007\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"aa731f04-cc4e-4349-9268-4476ff04b473\\\",\\\"ParentID\\\":\\\"bfca703b-1720-4a67-b0a4-2f6146c820aa\\\",\\\"Type\\\":\\\"folder\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Marsiling Secondary School\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:20.983\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"af650810-0538-432e-8bf3-47429eb17d27\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"finger paintings.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:35.65\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"ddac31de-2b67-4f56-aefd-508a8f49926f\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"My Love.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:56.55\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"f2454474-d834-4bd1-992e-548cdc2734c1\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"boat.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:28.813\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"e1f5be01-29c7-4ca9-ae6f-5ddf8638cc67\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Davinshi.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:34.687\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"ff3a7365-7b4e-4a46-b545-6a2f889ff898\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"landscape paintings.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:44.48\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"327bf043-1e88-4265-ba5e-6de8394a0d84\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"lord rama.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:47.753\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"1d8a01de-da06-466d-8b7d-6e0bb8478d5e\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"intimacy worship.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:41.617\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"f23103ec-0d8c-407b-9f20-719f0577c274\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Coast of Sicily.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:32.187\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"374779d5-16e9-417f-808f-87fcf85035b0\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"misty mood leonid.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:54.203\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"f0bb2dc7-eac3-407d-a85a-886aaf161fc2\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"boat.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:28.907\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"607ee7b8-7287-4f3f-9867-8a8069562d3c\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"jpg\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Ballet.jpg\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:24.167\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"246b349e-ab32-407a-90ff-8df18bbabc68\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"Ballet.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:23.917\\\",\\\"Status\\\":0,\\\"Mark\\\":null},{\\\"ID\\\":\\\"457d722f-a675-4523-bd83-8f309dcd254e\\\",\\\"ParentID\\\":\\\"187a064e-ffea-45a2-9264-9acecff911e1\\\",\\\"Type\\\":\\\"txt\\\",\\\"OwnerID\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"Name\\\":\\\"finger paintings.txt\\\",\\\"CreatedBy\\\":\\\"5bd087f0-070d-48bd-98b4-10ffa4b3b792\\\",\\\"CreatedDate\\\":\\\"2015-06-05T04:11:39.017\\\",\\\"Status\\\":0,\\\
Which I think the HTTP POST Response is reading the string as a verbatim string.
Any idea how can i fix it ?
Thanks !
When I run your code, the output of Encoding.Default.GetString(response) is exactly the string you posted at the top of your question.
The excessively backslash-escaped string appears in the Visual Studio debugging window simply because VS escapes special characters when displaying a string, but if you try to save this string into a file or use it in any other way in your code, you will see that only the double quote marks are escaped, like the string at the top of your question.
I found out that the API will automatically convert the object to json format.
The problem occur when I try to serialize the object before sending trough the API.Hence, like what Denis Yarkovoy said. It's double serialized.
I'm implementing a plugin (POST Quote Create, Synchronous, Sandbox) to make it so that Notes are copied to the new record when a quote is revised.
My plugin boils down to this (snippet):
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var Service = serviceFactory.CreateOrganizationService(context.UserId);
var notesQuery = new QueryExpression("annotation");
notesQuery.ColumnSet = new ColumnSet(true);
notesQuery.Criteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression("objecttypecode", ConditionOperator.Equal, "quote"),
new ConditionExpression("objectid", ConditionOperator.Equal, revisedQuoteId)
}
};
var notes = Service.RetrieveMultiple(notesQuery).Entities;
foreach (var n in notes)
{
var newNote = new Entity("annotation");
newNote.Attributes.Add("ownerid", n.GetAttributeValue<EntityReference>("ownerid"));
newNote.Attributes.Add("objectid", new EntityReference("quote", sourceEntity.Id));
newNote.Attributes.Add("objecttypecode", "quote");
newNote.Attributes.Add("subject", n.GetAttributeValue<string>("subject"));
newNote.Attributes.Add("notetext", n.GetAttributeValue<string>("notetext"));
newNote.Attributes.Add("isdocument", n.GetAttributeValue<bool>("isdocument"));
if (n.GetAttributeValue<bool>("isdocument"))
{
newNote.Attributes.Add("filesize", n.GetAttributeValue<int>("filesize"));
newNote.Attributes.Add("documentbody", n.GetAttributeValue<string>("documentbody"));
newNote.Attributes.Add("filename", n.GetAttributeValue<string>("filename"));
newNote.Attributes.Add("mimetype", n.GetAttributeValue<string>("mimetype"));
}
Service.Create(newNote);
}
Basically, I copy everything over, including an eventual attachment. Everything seems fine, the new revision shows fields, detail records and notes properly... everything but the attachment of the notes.
If I have a single note, with an attached test.txt which content is:
Test attachment
The OrganizationData service reads as follows:
<d:FileName>test.txt</d:FileName>
<d:FileSize m:type="Edm.Int32">39</d:FileSize>
<d:DocumentBody>H4sIAAAMaVMA/wtJLS5RSCwpSUzOyE3NK+HlAgCLmj1zEQAAAA==</d:DocumentBody>
Its "clone" has the correct subject and text, and also shows a test.txt attached which content is
‹ iS ÿI-.QH,)ILÎÈMÍ+áå ‹š=s
mimetype and filesize (while checking odata, I noticed that filesize is not actually correct!) appear to be correct (aka: the same as the original note I'm trying to copy), but OData seems to confirm something's off (it's different!):
<d:FileName>test.txt</d:FileName>
<d:FileSize m:type="Edm.Int32">60</d:FileSize
<d:DocumentBody>H4sIAED6aVMA/5Pv5mBg4MkMZvjP7amrF+iho+npc+6E71nth0+ZGLpn2RYLMjAwAABXqCwTJQAAAA==</d:DocumentBody>
The test.txt file was created from a command prompt (COPY CON test.txt, type, CTRL+Z).
I tried to change the file, and created a test.pdf through PDFCreator: AcroRead in turn whines and says the document is corrupted (so it seems like the issue is mimetype-agnostic).
I also tried re-implementing the same code through early binding (via the CRMSVCUTIL-generated classes) but it yields the exact same result (garbage instead of the attachment contents).
I attempted to hand-craft the documentbody like this:
// "VGVzdCBhdHRhY2htZW50" is Base64 for "Test attachment"
newNote.Attributes.Add("documentbody", "VGVzdCBhdHRhY2htZW50");
and the created file is correct.
I can't figure out what's going on: as far as I know, documentbody is supposed to be a Base64-encoded string which (again, as far as I know) shouldn't be any different when copied around. What am I missing ?
For reference, CRM is updated to UR13 but I repro'd it on a UR16 environment.
EDIT: Does NOT work (only for CRM 4)
Try this (not verified):
var notes = Service.RetrieveMultiple(notesQuery).Entities;
foreach (var newNote in notes)
{
newNote.annotationid = null;
newNote.Attributes.Add("objectid", new EntityReference("quote", sourceEntity.Id));
newNote.Attributes.Add("objecttypecode", "quote");
Service.Create(newNote);
}
Just saw this, in an article from MSDN:
Annotation setupAnnotation = new Annotation()
{
Subject = "Example Annotation",
FileName = "ExampleAnnotationAttachment.txt",
DocumentBody = Convert.ToBase64String(
new UnicodeEncoding().GetBytes("Sample Annotation Text")),
MimeType = "text/plain"
};
I see the document body is encoded according to the Unicode encoding. Maybe you should try to retrieve the encoding from the file and convert it to a string accordingly.
I have an aspx page that contains regular html, some uicomponents, and multiple tokens of the form {tokenname} .
When the page loads, I want to parse the page content and replace these tokens with the correct content. The idea is that there will be multiple template pages using the same codebehind.
I've no trouble parsing the string data itself, (see named string formatting, replace tokens in template) my trouble lies in when to read, and how to write the data back to the page...
What's the best way for me to rewrite the page content? I've been using a streamreader, and the replacing the page with Response.Write, but this is no good - a page containing other .net components does not render correctly.
Any suggestions would be greatly appreciated!
Take a look at System.Web.UI.Adapters.PageAdapter method TransformText - generally it is used for multi device support, but you can postprocess your page with this.
I'm not sure if I'm answering your question, but...
If you can change your notation from
{tokenname}
to something like
<%$ ZeusExpression:tokenname %>
you could consider creating your System.Web.Compilation.ExpressionBuilder.
After reading your comment...
There are other ways of getting access to the current page using ExpressionBuilder: just... create an expression. ;-)
Changing just a bit the sample from MSDN and supposing the code of your pages contain a method like this
public object GetData(string token);
you could implement something like this
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
Type type1 = entry.DeclaringType;
PropertyDescriptor descriptor1 = TypeDescriptor.GetProperties(type1)[entry.PropertyInfo.Name];
CodeExpression[] expressionArray1 = new CodeExpression[1];
expressionArray1[0] = new CodePrimitiveExpression(entry.Expression.Trim());
return new CodeCastExpression(
descriptor1.PropertyType,
new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(),
"GetData",
expressionArray1));
}
This replaces your placeholder with a call like this
(string)this.GetData("tokenname");
Of course you can elaborate much more on this, perhaps using a "utility method" to simplify and "protect" access to data (access to properties, no special method involved, error handling, etc.).
Something that replaces instead with (e.g.)
(string)Utilities.GetData(this, "tokenname");
Hope this helps.
Many thanks to those that contributed to this question, however I ended up using a different solution -
Overriding the render function as per this page, except I parsed the page content for multiple different tags using regular expressions.
protected override void Render(HtmlTextWriter writer)
{
if (!Page.IsPostBack)
{
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(stream))
{
HtmlTextWriter htmlWriter = new HtmlTextWriter(streamWriter);
base.Render(htmlWriter);
htmlWriter.Flush();
stream.Position = 0;
using (System.IO.StreamReader oReader = new System.IO.StreamReader(stream))
{
string pageContent = oReader.ReadToEnd();
pageContent = ParseTagsFromPage(pageContent);
writer.Write(pageContent);
oReader.Close();
}
}
}
}
else
{
base.Render(writer);
}
}
Here's the regex tag parser
private string ParseTagsFromPage(string pageContent)
{
string regexPattern = "{zeus:(.*?)}"; //matches {zeus:anytagname}
string tagName = "";
string fieldName = "";
string replacement = "";
MatchCollection tagMatches = Regex.Matches(pageContent, regexPattern);
foreach (Match match in tagMatches)
{
tagName = match.ToString();
fieldName = tagName.Replace("{zeus:", "").Replace("}", "");
//get data based on my found field name, using some other function call
replacement = GetFieldValue(fieldName);
pageContent = pageContent.Replace(tagName, replacement);
}
return pageContent;
}
Seems to work quite well, as within the GetFieldValue function you can use your field name in any way you wish.