locked
How do I get a file from Sharepoint and attach it to CRM email? RRS feed

  • Question

  • Hi,

    I am writing a plug-in that will execute every few weeks as part of a workflow.  It will get a bunch of contacts and send them an email, attaching a MS Word document that is stored in a MOSS document library.  I understand how to programmatically create an email, but I don't understand how to make an attachment, and I don't know how to get a file from sharepoint in a format that allows me to attach it to an email.  I have gotten as far as getting the GUID from a document in a sharepoint library, but I do not know what to do with it....get it as an object, a stream, or what....and I guess the answer to that depends on what I need to attach it to an email sent through CRM.  There doesn't seem to be a lot of code out there about using the two products together like this.

    Thanks for any help,

    Pete

    Tuesday, May 4, 2010 3:34 PM

Answers

  • We've done this recently, though unfortunately I'm not able to make the code publicly available. However, the general steps I'd use are:

    1. Read the document contents from SharePoint using an HttpWebRequest (providing you know the document's Url, which should be straightforward), and read the data into a byte array (I'd use a BinaryReader)
    2. Create an instance of the activitymimeattachment entity using the CRM web services. Populate the body attribute with a base64 encoded string of the byte array from step 1 - use Convert.ToBase64String

    An extra thing you can do is read the ContentType form the HttpWebResponse in step 1, and write it to the mimetype property in step 3

     

     


    Microsoft CRM MVP - http://mscrmuk.blogspot.com  http://www.excitation.co.uk

     

    • Marked as answer by Jim Glass Jr Thursday, May 6, 2010 5:11 PM
    Tuesday, May 4, 2010 4:26 PM
    Moderator

All replies

  • Hi.

    do these  steps.

    1)  Download the file(or only get  the  stream object)  from  the sharepoint  document  library to your local folder insde the workflow, use  the  code below

    http://www.codeproject.com/KB/sharepoint/Anti_Shunter.aspx

    2) once you have the file  or  the stream,  you can  use  the below  code to  attach the file/stream and send  it.

    activitymimeattachment attach = new activitymimeattachment();
                    attach.activityid = new Lookup(EntityName.email.ToString(), createdEmailGuid);
                    attach.body = System.Convert.ToBase64String(result);
                    attach.subject =
                    attach.filename = "Report.xls";
                    attach.filesize = new CrmNumber(result.Length);
                    attach.mimetype = @"application/vnd.ms-excel";

                    crmservice.Create(attach);

    SendEmailRequest sendrequest = new SendEmailRequest();
                    sendrequest.EmailId = createdEmailGuid;
                    sendrequest.TrackingToken = "";
                    sendrequest.IssueSend = true;

                    crmservice.Execute(sendrequest);

    http://a33ik.blogspot.com/2009/08/custom-workflow-action-which-renders.html

     

     

     


    Muhammad Ali Khan
    My MS CRM blog
    • Proposed as answer by Aarch Wednesday, May 5, 2010 5:56 AM
    Tuesday, May 4, 2010 4:21 PM
  • We've done this recently, though unfortunately I'm not able to make the code publicly available. However, the general steps I'd use are:

    1. Read the document contents from SharePoint using an HttpWebRequest (providing you know the document's Url, which should be straightforward), and read the data into a byte array (I'd use a BinaryReader)
    2. Create an instance of the activitymimeattachment entity using the CRM web services. Populate the body attribute with a base64 encoded string of the byte array from step 1 - use Convert.ToBase64String

    An extra thing you can do is read the ContentType form the HttpWebResponse in step 1, and write it to the mimetype property in step 3

     

     


    Microsoft CRM MVP - http://mscrmuk.blogspot.com  http://www.excitation.co.uk

     

    • Marked as answer by Jim Glass Jr Thursday, May 6, 2010 5:11 PM
    Tuesday, May 4, 2010 4:26 PM
    Moderator
  • Thank you both very much for the tips, they were helpful.

     

    This is the code I have:

    public static void GetDocFromSP()
            {
                HttpWebRequest request;
                HttpWebResponse response = null;

                byte[] fileContents;

                try
                {
                    // Create the HttpWebRequest object
                    request = (HttpWebRequest)WebRequest.Create("http://mosstest/PLStore/Document Library/Generic_01_01.docx");
                    request.Credentials = System.Net.CredentialCache.DefaultCredentials;
                    request.Timeout = 10000;
                    request.AllowWriteStreamBuffering = false;

                    // Get the response
                    response = (HttpWebResponse)request.GetResponse();
                    Stream s = response.GetResponseStream();

                    // Read the response into a binary array
                    BinaryReader binReader = new BinaryReader( s);
                    byte[] testArray = new byte[4096];
                    int count = binReader.Read(testArray, 0, 4096);
                    fileContents = binReader.ReadBytes( count);

                    activitymimeattachment attach = new activitymimeattachment();
                    attach.body = System.Convert.ToBase64String(fileContents);
                    attach.mimetype = response.ContentType;

                    response.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }

    One problem is that I don't know how to the size of the binary array, the stream throws an error when I try to get the length, saying it does not support seek operations.  It has been many years since I've done stream I/O.

     

    I looked around and also read about using WSCopy.  What is the difference between this and the HttpWebRequest? :

    //Copy WebService Settings
                string webUrl = @"http://mosstest/plstore";
                Common.MossDevCopy.Copy copyService = new Common.MossDevCopy.Copy();
                copyService.Url = webUrl + @"/_vti_bin/copy.asmx";
                copyService.Credentials = System.Net.CredentialCache.DefaultCredentials;

                //Source and Destination Document URLs
                string sourceUrl = @"http://mosstest/Shared Documents/AS_01_01.docx";

                //Variables for Reading metadata’s of a document
                Common.MossDevCopy.FieldInformation fieldInfo = new Common.MossDevCopy.FieldInformation();
                Common.MossDevCopy.FieldInformation[] fieldInfoArray = { fieldInfo };

                //Receive a Document Contents  into Byte array (filecontents)
                //byte[] fileContents = new Byte[4096];
                byte[] fileContents;
                copyService.GetItem(sourceUrl, out fieldInfoArray, out fileContents);

                activitymimeattachment attach = new activitymimeattachment();
                attach.body = System.Convert.ToBase64String(fileContents);
                attach.mimetype = @"application/vnd.ms-word.12";

    • Edited by PGB999 Wednesday, May 5, 2010 7:57 PM
    Wednesday, May 5, 2010 7:12 PM
  • did you  try  s.Length?  it  should  work as  described  in the  link  below.

    http://www.codeproject.com/KB/sharepoint/Anti_Shunter.aspx

     


    Muhammad Ali Khan
    My MS CRM blog
    Wednesday, May 5, 2010 7:26 PM
  • did you  try  s.Length?  it  should  work as  described  in the  link  below.

    http://www.codeproject.com/KB/sharepoint/Anti_Shunter.aspx

     


    Muhammad Ali Khan
    My MS CRM blog

    No, when I try to use s.Length I get a System.NotSupportedException, "This stream does not support seek operations."  I'm looking to see why I get that but no luck so far.

     

    EDIT: I saw a post that gave me this idea, and it seems to work:

    fileContents = binReader.ReadBytes((int)response.ContentLength);

     

    Pete

    Wednesday, May 5, 2010 7:46 PM