This blog is an extension of the amazing Melvin Hidalgo’s document: http://scn.sap.com/docs/DOC-33266.

Our objective is to send an email with a custom attachment (or pdf generated by the studio).

In order to do this, I created a custom BO with an element DUMMY and an action “SENDMAIL”.

1.PNG

In the implementing script for the action, I followed the Melvin’s instructions by creating an EmailActivity instance with a subject and then I added parties and the email body:

2.PNG

3.PNG

Finally our code in order to add some attachments. The first one is an empty attachment (just for test, but you can add a custom binary (base64) content. The second one is a pdf generated using a form binded to our custom BO containing the dummy element:

4.PNG

Result:

5.PNG

6.PNG

Unfortunately it seems that actually, there is no way to add a name for the sent attachments (if someone succeeds to do this please contact me).

To report this post you need to login first.

34 Comments

You must be Logged on to comment or reply to a post.

  1. Rei Kasai

    Hey guys, there is also a very flexible key user based email/task notifications feature that is enabled for the Cloud for Customer BOs so you dont have to write code to do rules based notifications which can be sent to named CRM users as well as to customer records. You can define any number of rules/conditions, define the content which may be HTML based templates, and then the recipient of that email/task. You can find this feature is Administrator or Application User Management Work Center -> Workflow -> Notification Rules

    Screen Shot 2013-12-12 at 9.53.00 AM.png

    (0) 
    1. Sathianarayanan Hari

      Hello Rei,

      The standard notification rule doesn’t support e-mail attachment. Because of this I have to develop a custom notification rule with attachment. Do you have any idea if this is in road map? Is there a way to enhance the standard notification rule to add attachments?

      Thanks,

      Hari

      (0) 
  2. Sachin Deshpande

    Hi Alessandro,

    Will the above code to attach a file to email, as it is, help me in following requirement too :

    Requirement: In Opportunity View -> My New Tab -> My Advanced List Pane -> My column -> here I want to provide some control in such a way that I should be able to add an attachment to this column, and ultimately to the list pane and Opportunity.

    * In properties, the display type My Column is set to File Upload. Is this correct ?

    * Also if this should be File Upload, do we need to provide any event for ‘OnFileSelect’ ?

    * Also do we need to provide a seperate dialog box and script to add an attachment, that will be triggered on selecting a file ?

    The FileUpload button allows me to select the file, but as I save the list and opportunity instance, it gets saved without any actual file uploaded as attachments. I am basically stuck here and not finding proper solution.

    Any pointers or help will be appreciated.

    Thanks.

    (0) 
  3. Fred Wang

    Hi Alessandro,

    there is some changes in activity BO, SAP standard DEV do not recommend  to use this method to send mail, because it may become invalid in the future, maybe 1402 version.

    I also don’t know other method to send mail, 🙂

    BTW: did you check the PDF file you send to other person, maybe you can’t open it successfully, because of encode problem in activity BO.

    Kind Regards.

    Fred

    (0) 
    1. Alessandro Iannacci Post author

      Hi Fred, I checked the PDF and is working.

      Thank you for the information, are you sure that this method will become unavailable? This is a very bad thing also because customers cannot decide to upgrade their tenant or not.

      For our project this is a requirement and cannot be fullfilled by in other ways

      (0) 
      1. Vinodkumar Kommineni

        Unfortunately even we are about to use this method in our requirements. So we should find some way to avoid it if this is the case.

        But can customers choose not to upgrade ? I believe at least multiple customer would share the same system with different tenants and one customer cannot say I do not want to upgrade. Probably someone from SAP should comment on this ? 

        Regards

        Vinod

        (0) 
        1. Jens Limbach

          Hi Vindod,

          Customers can definetly not choose to not upgrade their tenant. Fred is also right that there will be a change for the Acitivity BO. I will try to get a statement regarding that or some additional information. But it will be next year I guess.

          Cheers,
          Jens

          (0) 
          1. Vinodkumar Kommineni

            Hi Jens,

            Thanks for the clarification and we would love to hear what SAP is working on or going to change in future so that we can align our developments accordingly. Thanks in advance.

            Regards

            Vinod

            (0) 
            1. Jens Limbach

              Hi all,

              I got an answer.

              1. The coding against the Acitivity BO should still work in 1402. But it will be deprecated, so partners need to change the coding to work with the new BusinessActivity BO.

              2. Using Activity BO for e-mailing in general: Actually this BO is for tracking business activites between sales reps and customers and not to be used as general “mailing tool (Though it can be used as such). There is an OutputRequest BO which might be released for such purpose. I will try to get more details on that.

              Cheers and happy new year,

              Jens

              (0) 
              1. Mani B

                Hi Jens,

                In the second point of your explanation you meant to say, we can’t create an emailActivity using ABSL logic even though we have feasibility of doing it in 1402??

                If yes, I did’t find the BO, RequestOutPut in the 1402 cloud studio repository..!!

                Is there any other way to create an EmailActivity ?? I know the Notification rule but i wanted to create an EmailActivity using ABSL logic?

                Regards,

                Mani

                (0) 
                1. Alessandro Iannacci Post author

                  Hi Mani.

                  See my sample code (its a little complicated but you can extract interesting lines):

                  /*

                      Add your SAP Business ByDesign scripting language implementation for:

                          Business Object: CustomerQuote

                          Node: Root

                          Event: BeforeSave

                         

                      Note:

                        – To access the elements of the business object node,

                          use path expressions, for example, this.<element name>.

                        – To use code completion, press CTRL+J.

                  */

                  import ABSL;

                  import AP.PC.ActivityManagement.Global;

                  import AP.CRM.Global;

                  import AP.Common.GDT as GlobalDataTypes;

                  import BASIS.Global;

                  //for the pdf

                  import DocumentServices.Global;

                  //Email vars

                  var elEmailRoot : elementsof Activity; 

                  var elEmailParty: elementsof Activity.Party;

                  var instEmail; 

                  var emailBody; 

                  var emailSubject:LANGUAGEINDEPENDENT_LONG_Text; 

                  var TXT_TYPE_BODY_TEXT = “10002”;

                  var elEmailTxtColl: elementsof Activity.TextCollection;

                  var elEmailTxtCollTxt: elementsof Activity.TextCollection.Text; 

                  var elEmailTxtCollTxtCntnt: elementsof Activity.TextCollection.Text.TextContent; 

                  var instEmailTxtColl; 

                  var instEmailTxtCollTxt; 

                  var instEmailTxtCollTxtCntnt;

                  var instEmailAttFld;

                  var doctype : GlobalDataTypes:DocumentTypeCode;

                  var binaryObject : BinaryObject;

                  var docDesc : GlobalDataTypes:Description;

                  var docName : GlobalDataTypes:LANGUAGEINDEPENDENT_Name;

                  var docAltName : GlobalDataTypes:LANGUAGEINDEPENDENT_Name;

                  var bin : BinaryObject.content;

                  //Other vars

                  var qryQuote_QueryByElements;

                  var selParamsQuote_QueryByElements;

                  var qryQuote_Result;

                  var qryInAppParty_QueryByElements;

                  var selParamsInAppParty_QueryByElements;

                  var qryInAppParty_Result;

                  var qryApprovedParty_QueryByElements;

                  var selParamsApprovedParty_QueryByElements;

                  var qryApprovedParty_Result;

                  var qryRejectedParty_QueryByElements;

                  var selParamsRejectedParty_QueryByElements;

                  var qryRejectedParty_Result;

                  var QuoteReplicatedParty : QuoteParty;

                  var ReplicatedParty : QuoteParty.ReplicatedParties;

                  var Quote : CustomerQuote;

                  var Party : CustomerQuote.Party;

                  var PartyColl : collectionof(CustomerQuote.Party);

                  var PartyCollCC : collectionof(CustomerQuote.Party);

                  var QuoteApprovalStatus = this.Status.ApprovalStatusCode;

                  var InAppEmailSent = this.approval_required_mail_sent;

                  var ApprovedEmailSent = this.approved_mail_sent;

                  var RejEmailSent = this.rejected_mail_sent;

                  //Email body vars

                  var id = this.ID.content.RemoveLeadingZeros();

                  var account;

                  if (this.BuyerParty.IsSet() && this.BuyerParty.Party.IsSet()){

                      account = this.BuyerParty.Party.CurrentName.PartyFormattedName.content;

                  }

                  var lv_title = “<div style=\”font-weight:bold;\”>Please find here enclosed the Quotation no. “+id+”</div><br /><br />”;

                  var lv_start = “<div style=\”background-color:#eeeeee;\”>”;

                  var lv_status = “<div><span style=\”font-weight:bold;\”>Status: </span>”+this.Status.ApprovalStatusCode.GetDescription()+”</div><br />”;

                  var lv_middle = “<br /><br />FOR YOUR INFORMATION<br /><br /><br />”;

                  var lv_customer;

                  if (this.BuyerParty.IsSet()){

                      lv_customer =  “<div><span style=\”font-weight:bold;\”>Customer number: </span>”+this.BuyerParty.PartyKey.PartyID.content.RemoveLeadingZeros()+”</div><br />”;

                  }

                  var lv_customer_n =  “<div><span style=\”font-weight:bold;\”>Customer name: </span>”+account+”</div><br />”;

                  var lv_resp;

                  if (this.EmployeeResponsibleParty.IsSet() && this.EmployeeResponsibleParty.Party.IsSet()){

                      lv_resp =  “<br/><div><span style=\”font-weight:bold;\”>Account manager: </span>”+this.EmployeeResponsibleParty.Party.CurrentName.PartyFormattedName.content+”</div><br />”;

                  }

                  var lv_segm =  “<br/><div><span style=\”font-weight:bold;\”>Segment: </span>”+this.Quot_Division.GetDescription()+”</div><br />”;

                  var lv_subseg =  “<div><span style=\”font-weight:bold;\”>SubSegment: </span>”+this.Quot_SubSegment.GetDescription()+”</div><br />”;

                  var lv_appfld =  “<div><span style=\”font-weight:bold;\”>Application field: </span>”+this.Quot_AppField.GetDescription()+”</div><br />”;

                  var lv_payterm;

                  if (this.CashDiscountTerms.IsSet()){

                      lv_payterm =  “<br/><div><span style=\”font-weight:bold;\”>Payment terms: </span>”+this.CashDiscountTerms.Code.GetDescription()+”</div><br />”;

                  }

                  var lv_incterm;

                  if (this.DeliveryTerms.IsSet() && (!this.DeliveryTerms.Incoterms.IsInitial())){

                      lv_incterm =  “<br/><div><span style=\”font-weight:bold;\”>Incoterms: </span>”+this.DeliveryTerms.Incoterms.ClassificationCode.GetDescription()+” “+this.DeliveryTerms.Incoterms.TransferLocationName+”</div><br />”;

                  }

                  var lv_endvald =  “<br/><div><span style=\”font-weight:bold;\”>End validity date: </span>”+this.ValidityPeriod.TimePointPeriod.EndTimePoint.Date.ToString()+”</div><br />”;

                  var lv_end = “</div><br />”;

                  //Code start!

                  QuoteReplicatedParty = QuoteParty.Retrieve(this.ID);

                  //Get old quote data

                  qryQuote_QueryByElements = CustomerQuote.QueryByElements;

                  selParamsQuote_QueryByElements = qryQuote_QueryByElements.CreateSelectionParams();

                  selParamsQuote_QueryByElements.Add(qryQuote_QueryByElements.ID.content, “I”,”EQ”, this.ID.content);

                  qryQuote_Result = qryQuote_QueryByElements.Execute(selParamsQuote_QueryByElements);

                  var cont = qryQuote_Result.Count();

                  if (cont == 0) { //creation fase

                      return;

                  }

                  //TO DECOMMENT

                  //Get all “in approval” party rules for notification

                  qryInAppParty_QueryByElements = QUOT_IN_APP_PARTIES.QueryByElements;

                  //selParamsInAppParty_QueryByElements = qryInAppParty_QueryByElements.CreateSelectionParams();

                  //qryInAppParty_Result = qryInAppParty_QueryByElements.Execute(selParamsInAppParty_QueryByElements);

                  qryInAppParty_Result = qryInAppParty_QueryByElements.Execute();

                  //Get all “approved” party rules for notification

                  qryApprovedParty_QueryByElements = QUOT_APPROV_PARTIES.QueryByElements;

                  //selParamsApprovedParty_QueryByElements = qryApprovedParty_QueryByElements.CreateSelectionParams();

                  //qryApprovedParty_Result = qryApprovedParty_QueryByElements.Execute(selParamsApprovedParty_QueryByElements);

                  qryApprovedParty_Result = qryApprovedParty_QueryByElements.Execute();

                  //Get all “rejected” party rules for notification

                  qryRejectedParty_QueryByElements = QUOT_REJEC_PARTIES.QueryByElements;

                  //selParamsRejectedParty_QueryByElements = qryRejectedParty_QueryByElements.CreateSelectionParams();

                  //qryRejectedParty_Result = qryRejectedParty_QueryByElements.Execute(selParamsRejectedParty_QueryByElements);

                  qryRejectedParty_Result = qryRejectedParty_QueryByElements.Execute();

                  //–

                  //Trace.Info(this.Task_SubStatus.content);

                  foreach (Quote in qryQuote_Result){

                      //Trace.Info(TaskSubStatus, “substatus 1”);

                      //Trace.Info(Task.Task_SubStatus.content, “substatus 2”);

                     

                      if ((QuoteApprovalStatus != Quote.Status.ApprovalStatusCode) ) { //The email starts if the approval status field changed

                          //In Approval, Approved, Rejected check

                          if ((QuoteApprovalStatus != “3”) && (QuoteApprovalStatus != “4”) && (QuoteApprovalStatus != “6”)){

                              return;

                          }

                         

                          //This check to avoid duplicates

                          if ((QuoteApprovalStatus == “3”) && (InAppEmailSent == true)){

                              return;

                          }else{

                              if (QuoteApprovalStatus == “3”){

                                  this.approval_required_mail_sent = true;

                              }else{

                                  this.approval_required_mail_sent = false;

                              }

                          }

                          if ((QuoteApprovalStatus == “4”) && (ApprovedEmailSent == true)){

                              return;

                          }else{

                              if (QuoteApprovalStatus == “4”){

                                  this.approved_mail_sent = true;

                              }else{

                                  this.approved_mail_sent = false;

                              }

                          }

                          if ((QuoteApprovalStatus == “6”) && (RejEmailSent == true)){

                              return;

                          }else{

                              if (QuoteApprovalStatus == “6”){

                                  this.rejected_mail_sent = true;

                              }else{

                                  this.rejected_mail_sent = false;

                              }

                          }

                          //Logic to select the party accordingly to the Status

                          foreach (Party in this.Party){

                          //select the party

                              foreach (ReplicatedParty in QuoteReplicatedParty.ReplicatedParties){

                              //if the party flag has been selected by the user add the party to the collection

                                  if ((ReplicatedParty.partyUUID.content == Party.PartyUUID.content) && (ReplicatedParty.partyRole == Party.RoleCode) && ReplicatedParty.partyFlag == true){

                                      if (QuoteApprovalStatus == “3”){

                                          foreach (var status_rule in qryInAppParty_Result.Where( n => n.PARTYFUNC.content.Trim() == Party.RoleCode.Trim() )){

                                              if (status_rule.TO == true){

                                                  PartyColl.Add(Party);

                                              }

                                              if (status_rule.CC == true ){

                                                  PartyCollCC.Add(Party);

                                              }

                                          }

                                      }

                                      if (QuoteApprovalStatus == “4”){

                                          foreach (var status_rule in qryApprovedParty_Result.Where( n => n.PARTYFUNC.content.Trim() == Party.RoleCode.Trim() )){

                                              if (status_rule.TO == true){

                                                  PartyColl.Add(Party);

                                              }

                                              if (status_rule.CC == true ){

                                                  PartyCollCC.Add(Party);

                                              }

                                          }

                                      }

                                      if (QuoteApprovalStatus == “6”){

                                          foreach (var status_rule in qryRejectedParty_Result.Where( n => n.PARTYFUNC.content.Trim() == Party.RoleCode.Trim() )){

                                              if (status_rule.TO == true){

                                                  PartyColl.Add(Party);

                                              }

                                              if (status_rule.CC == true ){

                                                  PartyCollCC.Add(Party);

                                              }

                                          }

                                      }

                                  }

                              }

                          }

                          //Email instance creation

                          emailSubject = “Quotation n° ” + id + ” ” + account; 

                          elEmailRoot.SubjectName = emailSubject; 

                          //CODE 1402

                          elEmailRoot.TypeCode = “39”;

                          instEmail = Activity.Create(elEmailRoot); 

                          //TO DECOMMENT

                          //Add parties

                          if (PartyColl.Count() == 0 && PartyCollCC.Count() == 0){

                              return;

                          }

                          foreach (Party in PartyColl){

                              //1402 elEmailParty.PartyKey.PartyID.content = Party.PartyKey.PartyID.content; 

                              elEmailParty.PartyName = Party.PartyKey.PartyID.content; 

                              instEmail.MessageToParty.Create(elEmailParty);   

                          }

                          foreach (Party in PartyCollCC){

                              //1402 elEmailParty.PartyKey.PartyID.content = Party.PartyKey.PartyID.content;     

                              elEmailParty.PartyName = Party.PartyKey.PartyID.content; 

                              instEmail.CopyMessageToParty.Create(elEmailParty);

                          }

                          //–

                          //TO REMOVE – Add parties

                          //elEmailParty.PartyKey.PartyID.content = “8000000102”; 

                          //instEmail.MessageToParty.Create(elEmailParty); 

                          //Create body

                          //instEmailTxtColl = instEmail.TextCollection.Create();

                          //elEmailTxtCollTxt.TypeCode.content = TXT_TYPE_BODY_TEXT;

                          //instEmailTxtCollTxt = instEmailTxtColl.Text.Create(elEmailTxtCollTxt);

                          //elEmailTxtCollTxtCntnt.Text.content = “<html><head></head><body>test<body></html>”; //                           Here the message itself

                          //instEmailTxtCollTxt.TextContent.Create(elEmailTxtCollTxtCntnt);

                          //Create att folder

                          instEmailAttFld = instEmail.AttachmentFolder.Create();

                          //Add html attachment as body (TODO)

                          docName = “body.html”;

                          doctype.content = “10001”;

                          binaryObject.mimeCode = “text/html”;

                          binaryObject.content = Binary.ParseFromString(“<html><head></head><body>”+lv_title+lv_start+lv_status+lv_middle+lv_customer+lv_customer_n+lv_resp+lv_segm+lv_subseg+lv_appfld+lv_payterm+lv_incterm+lv_endvald+lv_end+”<body></html>”); //bin;

                          //binaryObject.content = Binary.ParseFromString(“<html><head></head><body>test<body></html>”);

                          instEmailAttFld.CreateFile(doctype, docName, docAltName, docDesc, binaryObject);

                         

                         

                          //PDF Generation

                          //var FormTemplateLanguage:LANGUAGEINDEPENDENT_MEDIUM_Text = “E”;

                          var PDF : BinaryObject;

                          //var FormTemplateCode : OutputRequestFormTemplateCode;

                          //FormTemplateCode.content = “C0002”; //Code is Form Template Header Code

                          //PDF = OutputManagementUtilities.GetPDF(this,FormTemplateCode,FormTemplateLanguage);

                          docName = “QuotationSnapshot.pdf”;

                          doctype.content = “10001”;

                          //binaryObject = PDF; //Binary.ParseFromString(Binary.ToBase64String(“iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==”)); //Binary.ParseFromString(“111111111”);

                          //instEmailAttFld.CreateFile(doctype, docName, docAltName, docDesc, binaryObject);

                          foreach (var pdf in this.AttachmentFolder.DocumentList){

                              if (pdf.MIMECode == “application/pdf”){

                                  binaryObject = pdf.FileContent.BinaryObject;

                                  instEmailAttFld.CreateFile(doctype, docName, docAltName, docDesc, binaryObject);

                              }

                              break;

                          }

                         

                         

                          instEmail.Send();

                      }else{

                          continue;

                     

                      }

                  }

                  (0) 
  4. preethi ande

    Hi Alessandro,

    I am implementing email template with business extension for travel and expense report.

    I am using these lines of code to send approval mail,

    EMailUtilities.SendEMail(lang, bcc, cc, toAddress, htmlContent, from name, subject);

    in absl file.

    I am not able to use your method to send emails, namespaces are not available,

    and we have requirement that need to attach files with an email,

    Please, can you give any suggestions to attach files in the SendEMail() method,

    Thanks & Regards,

    Preethi Ande

    (0) 
    1. Alessandro Iannacci Post author

      Hi preethi,

      with version 1402 the ActivityTask BO is no longer available. You should use the bo Activity from the namespace AP.PC.ActivityManagement.Global.

      Hope this helps

      (0) 
      1. preethi ande

        Thanks for your reply Alessandro,

        Our sdk version is 1405, am getting compilation error with this namespace also AP.PC.ActivityManagement.Global.


        So am not able to work with the above code,

        Any more suggestions please..

        (0) 
  5. Puneet Mittal

    Dear Experts,

    I have added custom button on my screen and have assigned this method. I have clicked on button send email but how we can check email is send successfully or not.

    Can you please help me ?

    Regards,

    Puneet Mittal

    (0) 
      1. SARUCHI PATHELA

        Hi Alessandro Iannacci

        Can you please guide me how to send custom PDF form in email attachment? I am able to send an email with a pdf attachment but i am unable to open it as it is giving some message as “………..it was set as an email attachment and wasn’t correctly decoded”

        Thanks

        Saruchi

        (0) 
          1. SARUCHI PATHELA

            Hi Alessandro Iannacci

            My requirement is to add a button on Tickets WC view in WC service. Button is Send Email. On click of that button an email should be triggered with an attachment of custom pdf form.

            1. I have made a custom pdf form and created a EC and a button preview on it and On click of that button I am able to see my form.

            2. But when I tried the same thing with Send Email button where I have created an action Send_Email which populates the Email Body with HTML text and in attachments I am passing the group code of my form I am not able to open the same. It does not gets opened up and gives some decoding issue

            I am attaching screenshots for action send_email. Am I missing something?

            /wp-content/uploads/2016/05/pic1_956352.png/wp-content/uploads/2016/05/pic2_956354.png/wp-content/uploads/2016/05/pic3_956355.png/wp-content/uploads/2016/05/pic4_956356.png/wp-content/uploads/2016/05/pic5_956357.png

            (0) 
            1. Alessandro Iannacci Post author

              Please try with a simple form with just one label, to understand if it is a problem with the email framework or with the generation of the pdf.

              Thanks

              (0) 
  6. SRI HARI

    Hi All,

    Since the EmailActivity is now deprecated, I am trying to make use of Activity BO to perform send mail, but could not achieve the same. i have these points unanswered:

    1. Without creating instance in Activity can I send the mail when Outlook is not configured?
    2. In Activity BO, Party.EmailURI is read only what can be done to specify the sender?

    Please guide.

    Thanks,

    Sri

     

    (0) 
  7. Sankaran A

    Thanks for this valuable blog.

    I have one requirement.  I need to send a mail if Sales Order is released.

    Mail Content:

    Body: <content>

    Attachment: If I click preview button in Sales Order screen, the same exact pdf need to send as mail.

    What is the group code for the Standard form? (Ex. Sales Order)

    Regarding my question, I have raised a separate thread. Please help me to solve this issue.

    https://answers.sap.com/questions/184326/how-to-send-mail-with-standard-document-as-an-atta.html 

    Regards

    Sankaran A

     

     

    (0) 

Leave a Reply