Mailkit MimeKit.MimeMessage error: Unknown initialization parameter: System.Byte[] - c#

I want to forward an email after add some comment to that. original email saved as eml file so first i load that file and then add my comment to body or attach some new files and then resend email to new email address.
var mail = new MimeKit.MimeMessage();
var file = System.IO.File.ReadAllBytes("sample.eml"));
var orgMessage = new MimeKit.MimeMessage(file);
var builder = new MimeKit.BodyBuilder();
builder.TextBody = "user comment";
builder.Attachments.Add(new MimeKit.MessagePart { Message = orgMessage });
mail.Body = builder.ToMessageBody();
First of all in line 3 i get this error:
Unknown initialization parameter: System.Byte[]
Second I read this great answer Forward email using MailKit (C#) and what is resent parameters for? if i set them my comment on forwarded email not set? and that email resent clearly without any change?

Unknown initialization parameter: System.Byte[]
This means that there is no MimeMessage constructor that takes a byte[] parameter.
In other words, you can't do this:
var file = System.IO.File.ReadAllBytes("sample.eml"));
var orgMessage = new MimeKit.MimeMessage(file);
The correct way to load a message from a file is to do this:
var orgMessage = MimeMessage.Load ("sample.eml");
Second I read this great answer Forward email using MailKit (C#) and what is resent parameters for? if i set them my comment on forwarded email not set? and that email resent clearly without any change?
The MimeMessage.Resent* properties are used only when forwarding a message without attaching it to a new message.
You need to pick only 1 of the 3 solutions in the answer of mine that you linked to.
If you are going to attach the original message (like you are doing), then you SHOULD NOT use the Resent properties of the MimeMessage.

Related

Docusign: Is there a way to create an envelope in the 'created' state and then put it into 'sent' later?

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);

Mailkit: fetch messages and copying them to MySQL, attachments to drive

I've been using this code of MailSystem.Net so far to get emails from an Imap INBOX and added options to retrieve mail using $"SENTSINCE {Date}".
string mailBox = "INBOX";
public IEnumerable<Message> GetMailsSince(string mailBox) {
return GetMails(mailBox, $"SENTSINCE {DateTime.Now.AddDays(-3).ToString("dd-MMM-yyyy")}").Cast<Message>();
}
private MessageCollection GetMails(string mailBox, string searchPhrase) {
Mailbox mails = Client.SelectMailbox(mailBox);
MessageCollection messages = mails.SearchParse(searchPhrase);
return messages;
}
But even after studying mailkit for hours I can't seem to distill out how to do the same thing. My goal is to get a list of message object whose properties I can then map to another class I created which writes it into a mysql database. I also want to save the attachments to disk. All this works fine so far but performance is an issue. I'm hoping mailkit will greatly improve that.
My main source has been the sample here but because I'm not familiar with async programming yet and treeviews it's hard to see through it.
How can I hard code that I want "INBOX" as ´IMailFolder´?
Where or how can I use the "SENTSINCE {Date}" filter in Mailkit?
How do I get an ´IEnumerable´ of Mailkits equivalent to the Message object in mailsystem (´IMessageSummary´ maybe)?
If you can point me to some code or even convert the linked MailSystem.Net example to Mailkit that would be fantastic.
MimeMessage is the equivalent of MailSystem.NET's Message object, but that's not what you want. What you want is MailKit's IMessageSummary which will allow you to download individual MIME parts (aka "attachments").
It also allows you to get summary information about the message (flags, received date (aka "InternalDate") pre-parsed/decoded common header values (such as subject, sender, recipients, etc) really quickly because the IMAP server has those pieces of information cached in its database for quick retrieval.
using (var client = new ImapClient ()) {
client.Connect ("imap.mail-server.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate ("username", "password");
// if you don't care about modifying message flags or deleting
// messages, you can open the INBOX in read-only mode...
client.Inbox.Open (FolderAccess.ReadOnly);
// search for messages sent since a particular date
var uids = client.Inbox.Search (SearchQuery.SentAfter (date));
// using the uids of the matching messages, fetch the BODYSTRUCTUREs
// of each message so that we can figure out which MIME parts to
// download individually.
foreach (var item in client.Inbox.Fetch (uids, MessageSummaryItems.BodyStructure MessageSummaryItems.UniqueId)) {
foreach (var attachment in item.Attachments.OfType<BodyPartBasic> ()) {
var part = (MimePart) client.Inbox.GetBodyPart (item.UniqueId, attachment);
using (var stream = File.Create (part.FileName))
part.ContentObject.DecodeTo (stream);
}
}
}
Note: Each property on IMessageSummary has a corresponding MessageSummaryItems enum value that you will need to use in order to have that property populated.
For example, if you want to use IMessageSummary.Envelope, you will need to include MessageSummaryItems.Envelope in your Fetch() request.
Since MessageSummaryItems is marked with the [Flags] attribute, you can bitwise-or enum values together like this:
MessageSummaryItems.BodyStructure | MessageSummaryItems.Envelope and both pieces of information will be fetched.
Update:
Here's the inefficient way that is closer to how MailSystem.NET does it.
using (var client = new ImapClient ()) {
client.Connect ("imap.mail-server.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate ("username", "password");
// if you don't care about modifying message flags or deleting
// messages, you can open the INBOX in read-only mode...
client.Inbox.Open (FolderAccess.ReadOnly);
// search for messages sent since a particular date
var uids = client.Inbox.Search (SearchQuery.SentAfter (date));
// using the uids of the matching messages, fetch the BODYSTRUCTUREs
// of each message so that we can figure out which MIME parts to
// download individually.
foreach (var uid in uids) {
var message = client.Inbox.GetMessage (uid);
foreach (var attachment in message.Attachments.OfType<MimePart> ()) {
using (var stream = File.Create (attachment.FileName))
attachment.ContentObject.DecodeTo (stream);
}
}
}
Note: if you care about saving message/rfc822 attachments, then take a look at this StackOverflow answer: MailKit save Attachments
The "Inbox" folder is always available on an IMAP mail acccount. With MailKit it is available as ImapClient.Inbox. For the date filtering you could use the DateSearchQuery class. The getting started page of MailKit pretty much covers all your questions.

Windows Phone 8 sendGridMessage Compile error

private async void sendMail(string from,string to, string subject,string text)
{
// Create network credentials to access your SendGrid account
string username = "xx";
string pswd = "xx";
MailMessage msg = new MailMessage();
NetworkCredential credentials = new NetworkCredential(username, pswd);
// Create the email object first, then add the properties.
// Create the email object first, then add the properties.
SendGridMessage myMessage = new SendGridMessage();
myMessage.AddTo("xx");
myMessage.Subject = "Testing the SendGrid Library";
myMessage.Text = "Hello World!";
myMessage.From = new MailAddress(from);
// Create an Web transport for sending email.
var transportWeb = new SendGrid.Web(credentials );
// Send the email.
await transportWeb.DeliverAsync(myMessage);
}
My application is Windows Phone 8.1, I try to send mail via sendGrid I created an account and include libraries to code but it gives 3 error:
error CS0570: 'SendGrid.SendGridMessage.From' is not supported by the language
error CS1502: The best overloaded method match for 'SendGrid.Web.Web(string)' has some invalid arguments
error CS1503: Argument 1: cannot convert from 'System.Net.NetworkCredential' to 'string'
I have used this site"https://azure.microsoft.com/tr-tr/documentation/articles/sendgrid-dotnet-how-to-send-email/" as reference.
Do errors stem from because app is a Windows Phone app or what?
And is there any other way to send an email by declaring "from" within code?
This isn't really an answer to your question, but it's important enough I made it an answer and not a comment.
This is not a secure way to send email from a mobile device, because you are giving the code that contains the credentials to users that install. All they need to do is inspect the traffic from your app and your SendGrid API key or account is compromised.
You need to make a request to some secure backend server (or provider, e.g. Parse or Azure), and then send the email from that server rather than the client app.
If you want to debug the code though, check out the readme and example on Github. Microsoft's docs go out of date rather quickly. https://github.com/sendgrid/sendgrid-csharp

Why ftp credentials are stripped away from email body when using MailMessage in C#?

I am dispatching emails at clients, notifying them for specific content deliveries and I have a problem with the containing ftp uri in mail body. I am constructing the ftp uri alongside with ftp credentials in the following format, but the credentials part is stripped away (the section user:pass#):
ftp://user:pass#server/relativepath/filename
The code is something like that:
mailTemplate += String.Format("File FTP URI: {1}<br>",
new Uri(ftpBaseLink, filename), filename);
and the email is dispatched with the following matter:
MailMessage message = new MailMessage(
mailSettings.Smtp.From,
mailTo,
subject,
mailMessage) { IsBodyHtml = true };
SmtpClient client = new SmtpClient();
client.Send(message);
Is there any clue how can I override this "normalization"?
I think that there was a general "tightening" of security a while back because of the way URLs containing user:pass were being mis-used to fool people into thinking they were clicking on a link to http://www.mybank.com when the link itself was http://www.mybank.com:blah#www.adodgysite.com/fake_bank_site. Users are wiser now, but it may be that its this "lockdown" that is affecting you.
My suggestion would be to concatenate the URI yourself, without using Uri
off the top, i'd look into what 'new Uri(ftpBaseLink, filename)' becomes as a string.

How can I send MIME data with an email using c# aspx

I want to send a password email to a user, however the customer wants an image embedded (inline) in the email.
I created an email, saved the data to a txt file, during my code I read in the template but when I send it the line endings are broken and therefore the MIME data is broken. I just get =3D
What am I doing wrong?
string FILENAME = Server.MapPath("~/GuestUserTemplate.txt");
StreamReader objStreamReader = File.OpenText(FILENAME);
string sEmailTemplate = "";
string input = null;
while ((input = objStreamReader.ReadLine()) != null)
{
sEmailTemplate = sEmailTemplate + input;
}
objStreamReader.Close();
/* send an email */
MailMessage msg = new MailMessage();
msg.IsBodyHtml = true;
msg.To.Add(new MailAddress(sToEmail));
msg.From = new MailAddress(sFromEmail);
msg.Subject = sEmailSubject;
msg.Body = sEmailTemplate;
//try
{
client.Send(msg);
}
//catch (Exception excm)
{
}
Just done a bit more detective work. The email I am sending out has this in the header:
MIME-Version: 1.0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Where as an email which has inline images has:
Content-class: urn:content-classes:message
MIME-Version: 1.0
Content-Type: multipart/related;
boundary="----_=_NextPart_001_01C9C98D.6552117E";
type="multipart/alternative"
It seems that I need to set the Content type to multipart but I am not sure how...
I'm not quite sure what kind of text you are loading (and appending to what?) but I would recommend you create a real template, e.g. your email text with placeholders that will be replaced with user's name, etc.
Use <img src="cid:logo.png" /> - for the inline image in the HTML body of the message (in your template).
You will then need to add the corresponding image to the LinkedResources collection of the MailMessage and set its ContentID header to "logo.png" or whatever you call it. After that go and send your mail (multipart content type will be set automatically for you based on the structure of the mail message).
P.S.: use SendAsync() or write the mail to the local pickup queue of your own smtp server, otherwise you tie up your ASP.NET worker thread. Connecting to remote smtp servers/web services etc. takes a considerable amount of time (compared to the request execution time) and the worker thread is sitting there waiting and unable to service other incoming requests.
You should use System.Net.Mail. Create a MailMessage, then add an attachment and send with SmtpClient.
Check your text file - it may be missing the expected line ending (Cr + Lf).
Change the while loop from:
while ((input = objStreamReader.ReadLine()) != null)
{
sEmailTemplate = sEmailTemplate + input;
}
To:
sEmailTemplate = sEmailTemplate + objStreamReader.ReadToEnd();
The bottom line is that you can't do this with System.Net.Mail.
Here is the problem you are running into.
Encodings.
Your orignal mail was saved with the quoted-printable encoding (hence the "=3D"s you are seeing) When you re-read this into the message, these will get double encoded. Encodings are using for protecting the message during SMTP transport.
Boundaries.
When a message is created, boundaries are used in the headers to tell the mail client the boundaries of different parts of the message. You are trying to take boundaries of one message, and merge them into a new message. Since System.Net.Mail doesn't give you enough control over the internal boundaries, you can't do this.
If you want to send an embedded image using System.Net.Mail, you will need to create the message using a Linked Resource. Here is a link with more:
http://systemnetmail.com/faq/4.4.aspx

Categories

Resources