I am writing a program that polls an incoming mailbox (to which anyone who knows about it can post), reformats the info, then forwards the mail on to the correct address according to a predefined convention. For example, the incoming mail has:
From = "anybody#somedomain.com"
To = "myincomingmailbox#mydomain.com"
Subject = "Subject"
Body = "recipient#anotherdomain.com+newline+Body"
Then I take that email, preserve the "From" and "Subject" fields, but I change the "To" address to recipient#anotherdomain.com, and format the rest of the body according to my template.
Thus far all OK - but I anticipate a problem with spam filters on the recipient domains, since they may react as if I'm spoofing the "From" address.
What is the correct way to preserve the headers from the original mail intact, such that all the SPF/DKIM headers remain on the outgoing email, and the recipient domains don't treat the incoming mail as possible spam/phishing mails?
Related
I need to send an emails (bulk sending), and I have two cases:
The same email sent into multiple recipients
Different emails sent into different recipients
How, in both cases, I can control statuses?
First case will return single x-message-id, but how it can be translated into separate status for each recipients? (delivered, opened and so on?)
Second case, I believe, need to be done by sending one-by one, is that correct? Or there is also method to send bulk emails in that case?
I'm using C# and official .NET library.
To send the same email sent to multiple recipients:
You can use the MailHelper.CreateSingleEmailToMultipleRecipients and you'll need to specify the text and HTML content in code. (Sample)
You can also use the MailHelper.CreateSingleTemplateEmailToMultipleRecipients method which will use a SendGrid Dynamic Email Template. In that case the email template is already stored in SendGrid and you simply provide the ID of the template.
There's a showAllRecipients named parameter which defaults to false. When false recipients cannot see other recipients, when true recipients can see other recipients.
I'll talk about retrieving the status's of the individual emails later.
To send different email to different people:
You can use MailHelper.CreateMultipleEmailsToMultipleRecipients which will use a single text and HTML body template, but you can add substitution tags and pass in substitution data so the email will be personalized for every recipient. (Sample)
You can construct a single MailMessage but use multiple Personalization objects to override any of the MailMessage properties for specific recipients. (Sample)
You can also construct multiple MailMessage objects and submit them individually to the API, although the above options are made for this scenario.
To send any of these emails, your API key must have the mail.send permission.
There are additional ways to send bulk email with SendGrid, which I documented here in much more detail.
As you noted, when you send email in bulk, only a single message ID is returned via the x-message-id header.
When you later try to retrieve the details using that message ID, you will not find any messages.
That is because the message ID in the x-message-id header is used as a base ID and the real message IDs will append another ID.
For example, x-message-id will return "W86EgYT6SQKk0lRflfLRsA", but when you retrieve one of the individual messages, it will looks something like this: "W86EgYT6SQKk0lRflfLRsA.filterdrecv-5645d9c87f-78xgx-1-62841247-82.1".
You can retrieve these messages via the E-Mail Activity API like this:
var queryParams = JsonSerializer.Serialize(new
{
query = $"msg_id LIKE '{messageId}%'",
limit = 10
});
var response = await client.RequestAsync(
method: SendGridClient.Method.GET,
urlPath: "messages",
queryParams: queryParams
);
Console.WriteLine(await response.Body.ReadAsStringAsync());
Take note of the query property which is has the $"msg_id LIKE '{messageId}%'" value.
This query will filter to messages that begin with the message ID returned from the bulk email (messageId), and as a result retrieve all the individual messages.
You cannot query these messages immediately after submitting the bulk email to SendGrid's queue as it takes some time for them to become available through the API.
In my code I queried these messages every 30 seconds until the count of the recipients in the bulk email matched the messages returned.
The resulting JSON data looks like this:
{
"messages": [
{
"from_email": "some#email.address",
"msg_id": "5QSczogTRHqFtiIkLxMtWA.filterdrecv-5645d9c87f-6r2ch-1-62847C63-2D.0",
"subject": "Sending with Twilio SendGrid is Fun",
"to_email": "some#email.address",
"status": "delivered",
"opens_count": 0,
"clicks_count": 0,
"last_event_time": "2022-05-18T05: 01: 05Z"
},
{
"from_email": "some#email.address",
"msg_id": "5QSczogTRHqFtiIkLxMtWA.filterdrecv-5645d9c87f-6r2ch-1-62847C63-2D.1",
"subject": "Sending with Twilio SendGrid is Fun",
"to_email": "some#email.address",
"status": "delivered",
"opens_count": 0,
"clicks_count": 0,
"last_event_time": "2022-05-18T05: 01: 05Z"
},
...
]
}
As you can see, this includes the status property.
Note: You must purchase additional email activity history to gain access to the Email Activity Feed API.
Note: To retrieve message via the Email Activity Feed API, your API key must have the email_activity.read permission.
This would be one way to retrieve the status of your email messages.
Another way to keep track of the status of email messages would be to create a public ASP.NET endpoint configure the URL as the SendGrid Event Webhook.
SendGrid will send an HTTP request to your ASP.NET endpoint for every event which you can use to update the status of email messages.
PS: You may already be doing this, but whether you're sending a single email to multiple recipients or multiple emails to multiple recipients, Twilio recommends setting the SendAt property on the SendGridMessage when sending bulk emails.
Quoting from the SendGrid docs:
This technique allows for a more efficient way to distribute large
email requests and can improve overall mail delivery time performance.
This functionality:
Improves efficiency of processing and distributing large volumes of email.
Reduces email pre-processing time.
Enables you to time email arrival to increase open rates.
Is available for free to all SendGrid customers.
I hope that answered all your questions, if not let me know. I can't wait to see what you build!
I want to be able to create an envelope and then email the link to the signer. The code segment I came up with is:
EnvelopesApi envelopesApi = new EnvelopesApi();
envDef.Status = "sent";
EnvelopeSummary envelopeSummary = envelopesApi.CreateEnvelope(accountId, envDef);
RecipientViewRequest viewOptions = new RecipientViewRequest()
{
ReturnUrl = "https://www.docusign.com/devcenter",
ClientUserId = signer.ClientUserId,
AuthenticationMethod = "email",
UserName = signer.Name,
Email = signer.Email // does NOT send an email
};
ViewUrl recipientView = envelopesApi.CreateRecipientView(accountId, envelopeSummary.EnvelopeId, viewOptions);
The code before this segment gets the account, signer an envelope definition, etc.
This code works fine if I set envDef.Status = "sent". If I do not set that status, I get an exception from the last line of code in this segment.
I want to just have the envelope go into created status, then get the URL and send the email in my own code that does relay email.
Or, can I supply an email address and have Docusign send the email? But, in that case, what if their email fails for some reason?
The bottom line is that I want a way to deal with the problem of how to re-send the link if the email fails to get sent.
Re your stated objective:
I want to just have the envelope go into created status, then get the URL and send the email in my own code that does relay email.
This approach is not recommended, since the URL that you obtain via CreateRecipientView will timeout in a short amount of time (I believe it's 5 minutes). In other words, if the recipient does not open the email that you send them and click the link to launch their signing session within that period of time, the link becomes invalid and they'll be unable to use it to access their signing session.
Instead of using CreateRecipientView, I'd recommend that you simply specify the recipient's info (name, email, etc.) as part of the envelope definition and then DocuSign will send the recipient an email that contains a link that they can use to access their Envelope. This link will be valid for days (not minutes, like the link that you generate yourself via CreateRecipientView), so there's no requirement that the signer act on it immediately. If for some reason the recipient misplaces or does not receive the email that DocuSign sends them, you can easily have DocuSign re-send that email notification by either using the DocuSign web UI or by using the UpdateRecipient API operation with resendEnvelope=true specified (as Frederic described in his answer).
Update #1
There's no way to retrieve a long-lived link that a recipient can use to initiate their signing session. A common way to address your scenario would be the following:
Send the signer an email that contains a link that leads them to a web page that you build -- and instructions for them to click that link to launch their Envelope whenever they are ready to review/sign the document(s). (The link URL would need to contain some sort of querystring parameters that your web page could use to identify the Envelope and Recipient.)
Design your web page such that when it receives an inbound request (as it would when the recipient clicks the link in the email you send them), it uses the information in the querystring parameters to identify the Envelope and Recipient, then issues a CreateRecipientView request to retrieve the URL that will launch that recipient's signing session, and finally, automatically redirects the user to the URL that the CreateRecipientView response returns, thereby opening the Envelope for the recipient to review/sign/submit.
By following a process like this, you're able to craft/send the email that the recipient receives (instead of relying upon DocuSign to do so), and can ensure that you're only retrieving the envelope URL whenever the user has indicated that they're ready to sign (thereby avoiding the potential of the short-lived link expiring before it's used).
Update #2
For an example of how to add recipient(s) to the EnvelopeDefinition object using the DocuSign C# SDK, see this "recipe" -- specifically, see the code within the requestSignatureOnDocumentTest method. It's basically a two-step process:
1) Define each recipient. For example:
// Add a recipient to sign the documeent
Signer signer = new Signer();
signer.Email = recipientEmail;
signer.Name = recipientName;
signer.RecipientId = "1";
2) Populate the Recipients property of the EnvelopeDefinition object with the recipient(s) that you create. For example:
envDef.Recipients = new Recipients();
envDef.Recipients.Signers = new List<Signer>();
envDef.Recipients.Signers.Add(signer);
I'm going to try to answer both of your inquiries :
1) The bottom line is that I want a way to deal with the problem of how to re-send the link if the email fails to get sent.
In order to re-send the DocuSign email to your recipients, you can use the UpdateRecipient() method as such (see my C# example below). This will re-trigger the signing email to be sent one more time to the transaction recipients :
RecipientsUpdateSummary recipientsUpdateSummary =
envelopeApi.UpdateRecipients(
accountId,
envelope.EnvelopeId,
envelope.Recipients,
new EnvelopesApi.UpdateRecipientsOptions { resendEnvelope = "true" });
Here is what the official documentation states :
2) Is there a way to create an envelope in the 'created' state and then put it into 'sent' later?
Yes, it is possible.
When you create your envelope, make sure to specify the "Created" status as below :
Status = "created"
Create your envelope :
envelopeApi.CreateEnvelope(accountId, envelope);
Then, when you're ready, change the envelope status to "sent". This will trigger the emails to the recipients. Voila !
Envelope updatedEnvelope = new Envelope
{
Status = "sent"
};
envelopeApi.Update(
accountId,
envelopeId,
updatedEnvelope);
After creating a "reply to all" from an incoming email, I need to remove recipients that are not allowed to get this reply. But after creating the reply message, the recipients Lists (ToRecipients, CcRecipients, BccRecipients) of the reply message are empty.
ResponseMessage responseMessage = email.CreateReply(true);
foreach (EmailAddress toRecipient in responseMessage.ToRecipients)
{
if (! _outboundEmailAdresses.Contains(toRecipient.Address))
{
responseMessage.ToRecipients.Remove(toRecipient.Address);
}
}
`
If I iterate through email.ToRecipients, I see all the recipients. If I iterate through responseMessage.ToRecipients, I can't see any recipients. Shouldn't email.CreateReply(true) copy the email.from and email.ToRecipients addresses to the responseMessage?
This one's a bit confusing. Basically the ResponseMessage class implements EWS's CreateItem operation with the ReferenceItemId element, which allows you to send minimal information to the server. The idea is the server already has most of the info it needs to send a reply (like the original body, recipient list, etc), so you don't need to re-send that information. So the ResponseMessage doesn't get a copy of the recipients from the EmailMessage, because it doesn't need it.
You'll want to check the recipients of the original message, plus the sender. If they don't contain an unwanted address, then you don't need to do anything. If they do, then you'll want to set ResponseMessage.ToRecipients. If you do this, you need to add all of the desired addresses. Touching ResponseMessage.ToRecipients overrides the original recipient list.
I'm using MailChimp for .NET sending mails, but the wrapper for the recipient doesn't contain a type, which the is necessary for sending massmails.
MailChimp.Types.Mandrill.Messages.Recipient recipient = new MailChimp.Types.Mandrill.Messages.Recipient(member.EMail, member.Name);
Is it me who has missed something?
Quoted from MailChimp. Scroll down to "Tips for creating your HTML Campaign".
MailChimp does not use a BCC field as each recipient on your list is hidden from all other recipients on your list. We deliver a completely separate copy of your email to each recipient on your list, allowing you to personalize your content for each recipient, track clicks and opens, and address each email to the recipient's name.
I decided to use MCAPI.NET and changed the source adding a attribute to Recipient with name "to".
Setting this attribute to value "BCC" solved the problem.
Note : MailChimp is a Newsletter sending software where Mandrill is a transactional mail sending component.
I am sending an email with System.Net.Mail and I want to protect my user from receiving urls through those emails.
I have already used HtmlEncode and it works if my form data is html or script but if the user types a normal url (e.g. www.stackoverflow.com) or an email address, the e-mail body itself creates a link - even though I set IsBodyHtml to false.
I would like to know how I could ensure that my entire email body text cannot be clicked and taken somewhere else.
Ps: I tried using UrlEncode but it 'breaks' the entire email message.
This is caused by the email client (Outlook, Gmail, etc.) parsing the URL for your convenience. If you look inside the Body property of the MailMessage object, you would have no HTML link (<a href=...).