Why client.GetMessage stucks in between? - c#

I am trying to download unseen emails from pop server.I am trying this code(copied from official site of openPop.net)
public static List<OpenPop.Mime.Message> FetchUnseenMessages(string hostname, int port, bool useSsl, string username, string password, List<string> seenUids)
{
// The client disconnects from the server when being disposed
using (Pop3Client client = new Pop3Client())
{
// Connect to the server
client.Connect(hostname, port, useSsl);
// Authenticate ourselves towards the server
client.Authenticate(username, password,AuthenticationMethod.UsernameAndPassword);
// Fetch all the current uids seen
List<string> uids = client.GetMessageUids();
// Create a list we can return with all new messages
List<OpenPop.Mime.Message> newMessages = new List<OpenPop.Mime.Message>();
// All the new messages not seen by the POP3 client
for (int i = 0; i < uids.Count; i++)
{
string currentUidOnServer = uids[i];
if (!seenUids.Contains(currentUidOnServer))
{
// We have not seen this message before.
// Download it and add this new uid to seen uids
// the uids list is in messageNumber order - meaning that the first
// uid in the list has messageNumber of 1, and the second has
// messageNumber 2. Therefore we can fetch the message using
// i + 1 since messageNumber should be in range [1, messageCount]
OpenPop.Mime.Message unseenMessage = client.GetMessage(i + 1);
// Add the message to the new messages
newMessages.Add(unseenMessage);
// Add the uid to the seen uids, as it has now been seen
seenUids.Add(currentUidOnServer);
}
}
// Return our new found messages
//client.Disconnect();
return newMessages;
}
}
When i debugged this code i found that code is stopping at
OpenPop.Mime.Message unseenMessage = client.GetMessage(i + 1);
And after that no debug buttons work. Even i press F10 then it does nothing.
If i dont debug code let the application run then it keeps running and never comes out of loop.
What i am doing wrong here?Thanks

Related

Sending an email batch with SendGrid v3

I have a usecase where I have 1000 emails with the bodies prepared (they are ready to send as is), a single sent from email address, 1000 recipients. I am using SendGrid API v3 in C#. I am trying to figure out how to bulk send them to the SendGrid API. This is my code:
private async Task SendBatchEmails(DataRowCollection emailDataRows)
{
var WriteToDatabaseCollection = new Dictionary<Guid, string>();
var emailObjectCollection = new List<SendGridMessage>();
foreach (DataRow emailDataRow in emailDataRows)
{
var emailObject = new SendGridMessage();
var to = (new EmailAddress(emailDataRow["RecipientEmailAddress"] + "", emailDataRow["RecipientName"] + ""));
var from = new EmailAddress(emailDataRow["SenderEmailAddress"] + "", emailDataRow["SenderName"] + "");
var subject = emailDataRow["Subject"] + "";
var text = emailDataRow["MessageBody"] + "";
var html = $"<strong>{emailDataRow["MessageBody"] + "" }</strong>";
var msg = MailHelper.CreateSingleEmail(from, to, subject, text, html);
emailObjectCollection.Add(msg);
}
await emailClient.SendBatchEmailsEmailAsync(emailObjectCollection);
dataContext.UpdateEmailResult(WriteToDatabaseCollection);
}
public async Task SendBatchEmailsEmailAsync(List<SendGridMessage> messages)
{
return await client.????(messages);
}
client is a SendGridClient, and the only option I have is: SendEmailAsync(msg)
How do I send a batch fo sendgrid messages?
Twilio SendGrid developer evangelist here.
There isn't a batch email send for emails with different bodies. Though you can send the same body to multiple addresses.
To send your 1000 emails you need to loop through your list of messages and call the API once per message.
If any of the emails you want to send has same body as others (you can't bulk send emails with different content as mentioned in the other answer), you could group them by body and then send in chunks. SendGridClient takes max 1000 at a time, so you'd also need to check for that. With something like this:
public class Email
{
string Content { get; }
string Address { get; }
}
Your code to group, chunk and send your emails in batches (where emails is a collection of Email objects) would look something like this:
var client = new SendGridClient("123456APIKEY");
var senderEmail = "someEmail";
var groupedByContent = emails.GroupBy(x => x.Content, x => x.Address);
foreach(var group in groupedByContent)
foreach(var recipientsBatch in group.Chunk(1000))
{
var message = new SendGridMessage();
// This extra index is needed to create separate personalizations, if you don't want recipients to see each others email
for (var i = 0; i < recipientsBatch.Length; i++)
message.AddTo(new EmailAddress { Email = recipientsBatch[i] }, i);
message.PlainTextContent = group.Key;
message.SetFrom(senderEmail);
var response = await client.SendEmailAsync(message);
// response processing code ...
}

C# mailkit shows error when inbox is empty

Below code works well, but the code will be checked every 5000ms, when the inbox folder is empty system shows an error.
We need to check inbox every 5000ms even it be empty we need to read it.
using (var client = new ImapClient())
{
client.Connect(EXT_IMAP_SERVER, EXT_IMAP_PORT, true);
client.Authenticate(EXT_USERNAME, EXT_PASSWORD);
var inbox = client.Inbox;
inbox.Open(FolderAccess.ReadWrite);
var LAST_MSG = inbox.GetMessage (inbox.Count - 1);
DATA = LAST_MSG.Subject;
if(DATA != null); // this condition didn't solve our issue
{
inbox.AddFlags(inbox.Count - 1, MessageFlags.Deleted, true);
}
client.Disconnect(true);
}
**ERROR:
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. (Parameter 'index')**
Instead of checking if last message was null, check the Count of messages and if it's more than 0, then you do what you need to do.
using (var client = new ImapClient())
{
client.Connect(EXT_IMAP_SERVER, EXT_IMAP_PORT, true);
client.Authenticate(EXT_USERNAME, EXT_PASSWORD);
var inbox = client.Inbox;
inbox.Open(FolderAccess.ReadWrite);
// THIS
if(inbox.Count > 0) {
var LAST_MSG = inbox.GetMessage (inbox.Count - 1);
// .....
}
client.Disconnect(true);
}

How to read latest email from Yahoo mail using pop3 c#

I want to read email from my yahoo mail account. I am using "OpenPop.Pop3" to read email from my yahoo mail account, I am using below code :-
using OpenPop.Pop3;
public DataTable ReadEmailsFromId()
{
DataTable table = new DataTable();
try
{
using (Pop3Client client = new Pop3Client())
{
client.Connect("pop.mail.yahoo.com", 995, true); //For SSL
client.Authenticate("Username", "Password", AuthenticationMethod.UsernameAndPassword);
int messageCount = client.GetMessageCount();
for (int i = messageCount; i > 0; i--)
{
table.Rows.Add(client.GetMessage(i).Headers.Subject, client.GetMessage(i).Headers.DateSent);
string msdId = client.GetMessage(i).Headers.MessageId;
OpenPop.Mime.Message msg = client.GetMessage(i);
OpenPop.Mime.MessagePart plainTextPart = msg.FindFirstPlainTextVersion();
string message = plainTextPart.GetBodyAsText();
}
}
}
return table;
}
Same code is able to access other mails emails like gmail,outlook but while working with yahoo mail emails i am able to get Subject, Date but when came to message part that is:
OpenPop.Mime.Message msg = client.GetMessage(i);
OpenPop.Mime.MessagePart plainTextPart = msg.FindFirstPlainTextVersion();
Its give error "The stream used to retrieve responses from was closed".
Here is the "StackTrace":
at OpenPop.Pop3.Pop3Client.IsOkResponse(String response)
at OpenPop.Pop3.Pop3Client.SendCommand(String command)
at OpenPop.Pop3.Pop3Client.Disconnect()
at OpenPop.Pop3.Pop3Client.Dispose(Boolean disposing)
at OpenPop.Pop3.Disposable.Dispose()
Please let me know if i missing something or doing something wrong.
Also I have make yahoo mail emails to be accessed anywhere using POP.
First, based on your code snippet, you are downloading each message 4 times. That's going to be super slow.
As far as why you are getting the error, I do not know. I do not get an error using MailKit:
using MimeKit;
using MailKit;
using MailKit.Net.Pop3;
public DataTable ReadEmailsFromId()
{
DataTable table = new DataTable();
try
{
using (Pop3Client client = new Pop3Client())
{
client.Connect("pop.mail.yahoo.com", 995, true); //For SSL
client.Authenticate("Username", "Password");
for (int i = client.Count - 1; i >= 0; i--)
{
var msg = client.GetMessage (i);
table.Rows.Add(msg.Subject, msg.Date);
string msdId = msg.MessageId;
string message = msg.TextBody;
}
}
}
return table;
}

How to get all the messages from the Imapclient folder?

I intended to get all my messages in the Inbox folder and put them into the datagridview component.But the sentence "var message = client.Inbox.GetMessage(uids.Count - i - 1);" throws an exception:The IMAP server did not return the requested message. Is there anything wrong with my code?
//get a imapclient and connect to the server
string loginemail = UserInfo.LoginEmail;
string password = UserInfo.LoginPassword;
var client = new ImapClient();
client.Connect("imap.qq.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate(loginemail, password);
client.Inbox.Open(FolderAccess.ReadOnly);
var uids = client.Inbox.Search(SearchQuery.All);
//get all the messages from the specified folder
for (int i = 0; i < uids.Count; i++)
{
dataGridView1.Rows.Add(1);
var message = client.Inbox.GetMessage(uids.Count - i - 1);
dataGridView1.Rows[i].Cells[0].Value = message.From.ToString();
if (message.Subject != null) { dataGridView1.Rows[i].Cells[1].Value = message.Subject.ToString(); }
else { dataGridView1.Rows[i].Cells[1].Value = ""; }
dataGridView1.Rows[i].Cells[2].Value = message.Date.ToString();
}
The only way to figure out the problem is to follow the directions in the MailKit FAQ to get a protocol log and look to see what the server is sending as a reply.

MailSystem.Net Delete Message, IndexOnServer Property = 0

I'm using MailSystem.NET and trying to delete a message from the server. The problem is the IndexOnServer property is 0, and I get the following error:
Command "store 0 +flags.silent (\Deleted)" failed : 121031084812790 BAD Error in IMAP command STORE: Invalid messageset
Here's my code:
Imap4Client client = new Imap4Client();
client.Connect(account.Server, account.Username, account.Password);
var inbox = client.SelectMailbox("Inbox");
MessageCollection messages = inbox.SearchParse("SINCE " + DateTime.Now.AddHours(-hours).ToString("dd-MMM-yyyy"));
foreach (Message newMessage in messages)
{
inbox.DeleteMessage(newMessage.IndexOnServer, true);
}
How do I get the correct index of the message so I can delete it?
Edit:
The problem with the suggestions using the standard 1-based loop is that the counter index won't be in sync with the message index, since in my case I'm searching to retrieve a specific subset of messages only (as I understand it).
Thank you.
You can try deleting by the UID which should be more reliable and unique to each message. This has worked well for me in the past.
Edit: Since deleting the message causes all the indexes to shift down by one, you can use two separate counters. One to keep track of when you have iterated through the entire box (messagesLeft) and the other will keep track of the current message index which will be decreased by 1 if a message is deleted (since it would move up one place in line).
Mailbox box = client.AllMailboxes["inbox"];
Fetch fetch = box.Fetch;
int messagesLeft = box.Count;
int msgIndex = 0;
while (messagesLeft > 0)
{
msgIndex++;
messagesLeft--;
Message email = fetch.MessageObject(msgIndex);
if (criteria)
{
box.UidDeleteMessage(fetch.Uid(msgIndex), true);
msgIndex--;
}
}
In response to your comment, here is a fuller example of how you can use the UID for deletion without being concerned with the numeric position / index.
class Email
{
int UID { get; set; }
DateTime Sent { get; set; }
public string Body { get; set; }
// put whichever properties you will need
}
List<Email> GetEmails(string mailbox);
{
Mailbox box = client.AllMailboxes[mailbox];
Fetch fetch = box.Fetch;
List<Email> list = new List<Email>();
for (int x = 1; x <= box.MessageCount; x++)
{
Message msg = fetch.MessageObject(x);
list.Add(new Email() { } // set properties from the msg object
}
return list;
}
void DeleteEmail(Email email, string mailbox)
{
Mailbox box = client.AllMailboxes[mailbox];
box.UidDeleteMessage(email.Uid, true);
}
static void Main()
{
List<Email> emails = GetEmails("inbox");
emails = emails.Where(email => email.Sent < DateTime.Now.AddHours(-hours))
foreach (Email email in emails)
DeleteEmail(email);
}
This is official example from documantation.
instead of inbox.search("all") change it to your search query, etc.
http://mailsystem.codeplex.com/discussions/269304
//action_id is the Message.MessageId of the email
//action_flag is the Gmail special folder to move to (Trash)
//copying to Trash removes the email from the inbox, but it can't be moved back once done, even from the web interface
public static void move_msg_to(string action_id, string action_flag)
{
Imap4Client imap = new Imap4Client();
imap.ConnectSsl("imap.gmail.com", 993);
imap.Login("heythatsme#gmail.com", "heythatsmypassword");
imap.Command("capability");
Mailbox inbox = imap.SelectMailbox("inbox");
int[] ids = inbox.Search("ALL");
if (ids.Length > 0)
{
Message msg = null;
for (var i = 0; i < ids.Length; i++)
{
msg = inbox.Fetch.MessageObject(ids[i]);
if (msg.MessageId == action_id)
{
imap.Command("copy " + ids[i].ToString() + " [Gmail]/" + action_flag);
break;
}
}
}
}
just add 1 to the message index.
foreach (Message newMessage in messages)
{
inbox.DeleteMessage(newMessage.IndexOnServer + 1, true);
}
Try deleting last message first then second last and then come to delete first message.
IF you delete and expunge have been set then message number changes.

Categories