CRM Plugin that Fires on Send Email - email

I'm trying to create plugin that fires when an email is sent.
At first I tried using SetState and SetStateDynamicEntity to when the status is changed to completed. However the plugin never gets fired when an email is sent.
So I tried using the "Send" message using OnExecute method. Is it possible to retrieve the sent email entity info? I'm stumped in trying to return the Entity. The code below keeps returning "The given key was not present in the dictionary" error message.
I tried using either "Entity" or "EntityReference" but no luck.
I know that the Send message returns the EmailId. Is the only way to return the Entity from this EmailId?
public override void OnExecute(IServiceProvider serviceProvider, IPluginExecutionContext context)
{
var trace = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
if (!context.InputParameters.Contains("EmailId"))
{
return;
}
var emailId = (Guid)context.InputParameters["EmailId"];
Entity emailEntity = (Entity)context.InputParameters["Target"];

So the way you mentioned is the only correct way to get email records. Totaling up:
Retrieve identifier of email from context.
Retrieve email record using crm endpoint.
Following article contains description that is relevant to CRM 4.0 - http://www.patrickverbeeten.com/Blog/2008/01/25/CRM-40-Plug-in-message-input-parameters haven't seen something similar that was done for CRM 2011/2013/2015/2016.

Related

Salesforce send Email by Apex

I'm making by a requirement a code able to send an E-mail to an specific list of E-mails, due the fact that I must to include the attachments of the record I decided to use an apex class instead an e-mail alert. This object (A custom object ) must populate some fields in an email template with some of the record´s fields. I implemented the following code
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(lista);
mail.setTemplateId('00X21000000QR22');
//mail.setWhatId(idMinuta);
mail.setTargetObjectId('005d0000005NMIx');
mail.setSaveAsActivity(false);
List<Messaging.Emailfileattachment> fileAttachments = new List<Messaging.Emailfileattachment>();
for (ContentVersion document: documents)
{
Messaging.Emailfileattachment efa = new Messaging.Emailfileattachment();
efa.setFileName(document.Title);
efa.setBody(document.VersionData);
fileAttachments.add(efa);
}
mail.setFileAttachments(fileAttachments);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
I understood that to make the fields merge it´s necesary to use the WhatId method. In the related code, I have commented it because It generates an error (INVALID_ID_FIELD, WhatId is not available for sending emails to UserIds.)
My question is, if is it possible to do this with a custom object. I´m a little confuse with salesforce documentation beacuse it looks like the method supports a custom object, or maybe If I am forggeting something to include in the code.
If i keep the WhatID line commented, effectively the email is sent with the attachments and the Template but it is not populated.
I really need this kind of solution because the org have in this object at least 20 email templates, for me will be easier just to pass the Id of the template instead of makig a code with 20 different html codes for each situation
Thanks a lot
Please publish this question at Salesforce StackExcahnge https://salesforce.stackexchange.com/

MVC5 Mailkit send email with incorrect Email address

I am trying to send emails using my MVC5 application. To do this, I have installed Mailkit v 1.22.0 through NuGet package manager. And this is how my code looks like:
var FromAddress = "no-reply#email.com";
var FromAddressTitle = "My Org";
var connection = ConfigurationManager.ConnectionStrings["SmtpServer"].ConnectionString;
var Email = new MimeMessage();
Email.From.Add(new MailboxAddress(FromAddressTitle, FromAddress));
var AddressArray = value.SentTo.Split(';');
foreach (var item in AddressArray)
{
Email.To.Add(new MailboxAddress(item));
}
Email.Subject = value.Subject;
Email.Body = new TextPart("html")
{
Text = value.Content
};
using (var client = new SmtpClient())
{
client.Connect(connection);
client.Send(Email);
}
return "Email Successfully Sent";
which works fine except if a wrong recipient Email address has been entered, the application does not detect if the Email was actually sent or not (client.Send(Email) returns void). Is there a way to know if it really ended up getting sent to the recipient or not? If it is not possible with Mailkit, is there any other NuGet package that can do this?
The reason that SmtpClient.Send() returns void is that the SMTP protocol does not specify whether the message gets delivered successfully. All it can do us tell the client that the messages was accepted by the server or not (in which case MailKit will throw an exception).
If you need to know whether the message was successfully delivered, you will need to check for bounce messages sent to you which could take minutes or even hours.
The first thing you'll have to do, however, is subclass SmtpClient and override the GetEnvelopeId and GetDeliveryStatusNotifications methods.
Then, when you receive a bounce message, the top-level MIME part will typically be a multipart/report (represented by a MultipartReport object when using MimeKit). This multipart/report will then contain a message/delivery-status MIME part (and possibly others), which will have a list of header-like fields that specify the details about the delivery status for 1 or more recipients.
MimeKit will parse a lot of this for you (e.g. it has a MessageDeliveryStatus class which contains a StatusGroups property that you will want to use. However, what MimeKit does not do is parse the individual field values (but they shouldn't be that difficult for you to do, typically a few Split(';')'s should be enough iirc for some quick & dirty parsing).
You will want to read the spec for this at https://www.rfc-editor.org/rfc/rfc3464
The MimeKit docs linked above specify which sections to look closely at (I think 2.2 and 2.3).
I would recommend looking specifically at the Original-Recipient and Action fields.
original-recipient-field =
"Original-Recipient" ":" address-type ";" generic-address
generic-address = *text
action-field = "Action" ":" action-value
action-value =
"failed" / "delayed" / "delivered" / "relayed" / "expanded"
You will also need the Original-Envelope-Id field to figure out which message is being reported on:
original-envelope-id-field =
"Original-Envelope-Id" ":" envelope-id
envelope-id = *text
The envelope-id text will be the same string returned by your GetEnvelopeId implementation in the SmtpClient class.

Workday: Put_Customer returning an error

We are using Snaplogic to load records into workday. Currently, extracting customer records from the source and trying to load them into workday using the object Put_Customer of web service Revenue_Management.
I was getting the following error:
But I'm not getting any category information from the source. So, I tried putting the value for Customer_Category_Reference as 1. But I ended up getting the following error.
The documentation for workday is not helpful and this has been a blocker for me for some time now.
Any help will be appreciated.
Update:
Trying to get customer categories using the Get_Customer_Categories object of Revenue_Management web service using Snaplogic. But getting the following error:
Failure: Soap fault, Reason: Processing error occurred. The task submitted is not authorized., Resolution: Address SOAP fault message and retry
Unfortunately I don't have access to a tenant at this time to validate . However it is likely to work based in prior experience . Perhaps you could create a customer in Workday, through the GUI. Then do get customer API call. Note the category reference . Then, use that in your put customer call
If you look at the API documentation, you will find that Put_Customer accepts a WID in the Customer_WWS_Data object. If you search for "Customer Categories" in Workday, you will likely find the report of the same name. Just select the category that you want your newly loaded customers to default to (click on the magnifying class, then on the ellipsis, Integration Ids, View Ids). The Workday ID will appear at the top.
I have not used the Revenue Management API, but my code for creating a position reference in the Compensation API is probably very similar to what you need to do for the Customer Category reference:
public static Position_ElementObjectType getPositionReference(string WID) {
return new Position_ElementObjectType {
ID = new Position_ElementObjectIDType[] {
new Position_ElementObjectIDType {
type = "WID",
Value = WID
}
}
};
}

programmatically mark a shipping email as sent

I have set up an observer to send out an email as soon as a tracking number is added to a shipment, but I need to be able to some how show in the admin that the email has been sent instead of displaying "the shipment email is not sent."
Here is the code I am currently using. There is an issue with it because it some how ends up sending out a ton of emails, as if it is some how stuck in a loop. I could really use some help in figuring out why this is happening.
class WR_TrackingEmail_Model_Observer
{
public function sendTrackEmail($observer)
{
$track = $observer->getEvent()->getTrack();
$shipment = $track->getShipment(true);
$shipment->sendEmail();
$shipment->setEmailSent(true);
$saveTransaction = Mage::getModel('core/resource_transaction')
->addObject($shipment)
->addObject($shipment->getOrder())
->save();
}
}
You are calling save() on the shipment object. The shipment class has an _afterSave() function that triggers save on the track objects. Since you are creating an observer for track_save_after, you are very likely causing a loop.

Changing the From field for an email activity in a plug-in

When an email is sent to a queue and there is a contact associated with the "From" email in CRM, upon promoting an email to an email activity the system automatically fills in the "From" field with the contact information. However, if a user with the same email exists in CRM, too, then the system always picks up the system user instead of the contact. I need to override this behaviour to ALWAYS pick up the contact if one with the email exists.
I created a post-operation plug-in (tried a pre-operation plug-in, too) for the event Create for email, trying to override the From field. The problem is, it does not work. When I debug the plug-in, it goes quietly past the assignment without any errors and then the same plug-in fires for the same email again. And again. And again.
When I try instead to create a new email and use the same ActivityList[] I was trying to use for the entity that triggered the event, it works. It seems that the problem is that CRM does not allow changing the From field from a plug-in, or am I doing something wrong? If it's a limitation enforced by CRM, is there a way around it?
My code is below:
var email = ((Entity)context.InputParameters["Target"]).ToEntity<Email>();
...
var oldFrom = ((EntityCollection)email.Attributes["from"]).Entities;
List<ActivityParty> newFrom = new List<ActivityParty>();
foreach (Entity party in oldFrom)
{
EntityReference entRef = (EntityReference)party.Attributes["partyid"];
if (entRef.LogicalName == SystemUser.EntityLogicalName)
user = userLogic.Get(new Guid(entRef.Id.ToString()));
if (user == null) return;
string emailAddress = user.InternalEMailAddress;
Contact contact = contactLogic.LookupPASIndividual("", emailAddress);
if (contact != null)
{ newFrom.Add(new ActivityParty() {PartyId = new EntityReference(Contact.EntityLogicalName, contact.ContactId.Value) });
}
else
return;
}
email.From = newFrom;
Update: So I registered the plug-in on Pre-validation now and it's not triggered when an email activity is created by a router, it IS triggered when a user creates an email in CRM though...
The problem is that you aren't changing the email which is processed at all.
var email = ((Entity)context.InputParameters["Target"]).ToEntity<Email>();
This line converts the record which is currently processed to an object of type email. You modify the record which is not in scope of the operation. You have to modify the From of the target (either directly or write it back).
For the processing stages: take a look at the Event Execution Pipeline. Pre-Validation is to early for your task. I'am not quite sure when the address resolution is done, but I would try to do your conversion Pre-Create.
I ended up using a workaround: created an async Post-Event that associates the email activity with the contact if a contact with the same email exists, leaving the user associated with the email in the "From" field.