What is the best way to be notified instant when mails or changes happens to the INBOX of my mailbox using MailKit??
I have been playing around with following events:
ImapClient.Inbox.CountChanged; This seems to work best when using Exchange servers, since they don't react at all on the MessageArrived event. Pff..
ImapClient.Inbox.MessagesArrived; This seems to work quiet well with open source mail servers, like SquirrelMail, but doesn't work at all with Exchange.
I want to be notified when new mails arrive to the mailbox, if any mails are moved/deleted, and if there any mails moved to this imap folder. Which approach should I take to get an event asap when something happens to my INBOX?? I want the best of both worlds.
And what is the ImapClient.Inbox.Subscribe(); used for??
The Subscribe and Unsubscribe methods just flag a folder (aka mailbox) as subscribed or unsubscribed - generally this is only used by mail clients to decide whether or not the user wants to see the folder in the default folder list.
The CountChanged event is emitted anytime MailKit gets an untagged "* # EXISTS" line from the IMAP server, typically as part of a response to a command that was just sent.
The MessagesArrived event is emitted immediately following the CountChanged event IF AND ONLY IF the new message count is larger than the old message count. Unfortunately, this is a badly designed/named event because it can be very misleading. Since the logic that determines whether or not to emit the event only has limited context (the old message count and the new message count), it can't accurately decide whether or not to emit this event.
Take the following situation for example:
When you open a folder, let's say that the message count is 10.
Now you expunge a handful of messages (5?) out of the folder... BUT, while the messages are being expunged, you get 2 new messages.
When the expunge command completes, the IMAP server replies back with "* 7 EXISTS"
Since 7 (the new message count) is less than 10 (the old message count), the MessagesArrived event will not be emitted.
I want to be notified when new mails arrive to the mailbox, if any mails are moved/deleted, and if there any mails moved to this imap folder.
If you want to know when new messages arrive, you need to listen to the CountChanged event and do your own book keeping to figure out if new messages arrived or if messages were moved/deleted out of the folder.
There's no way to distinguish between messages being moved into the folder vs new messages being delivered to the folder (unless you are doing the moving).
Which approach should I take to get an event asap when something happens to my INBOX??
If your server supports the IDLE extension, you'll probably want to look into using the ImapClient.Idle() (or IdleAsync()) method since the CountChanged event will only be emitted when it receives a "* # EXISTS" response from the server, and an IMAP server will only send that response as part of a response to a command from the client or if the client is in the IDLE mode.
If your server does not support the IDLE extension, you will need to "ping" the IMAP server using the ImapClient.NoOp() method (which is a dummy command that doesn't do anything) periodically in order to check if any new messages have arrived since the last command you sent.
There's an ImapIdle sample in MailKit's GitHub repository to see how to use it.
Related
I have 3 machines, let's call them A, B (both servers) and Dev (my local machine).
I want to send a message queue item from A to B.
The actual C# code I have is rather simple and honestly, I really do not think it is problem here. (It's a webapi that takes a POSTed object and just shoves it down the queue).
I can send these messages just fine from Dev to B (while logged into a domain admin account) without a problem and I can inspect the body of the messages. However I cannot send messages from A to B. The private queue on B is set to allow "Everyone" the "Full Control" permissions.
If I pause the outbound queue on A and send the messages, they sit in the outbound queue and the body is exactly as I would expect it to be, but when I resume that outbound queue again, they are never received on the other end at B.
I can't figure out what's going on for the life of me. I tried the 'TCP' method but I need to refer to my queues by machine name not IP.
For reference, the code used to send the message is:
using (var queue = new MessageQueue($"FormatName:Direct=OS:MachineB\\private$\\Queue"))
{
var queueItem = new QueueItem();
queueItem.Object = this.postedObject;
var message = new System.Messaging.Message(queueItem);
queue.Send(message);
}
For reference and anyone else who comes across this:
The project sending the messages to the queue was a webapi. It was running under the AppPoolIdentity account in IIS and despite the receiving queue allowing Everyone access, it was denying these messages, but gracefully. So the webapi would fire the message and wouldn't throw any exceptions, it'd hit the outbound, but then never arrive.
We switched the account to NetworkService and it worked just fine.
I have a couple of queues where certain information is queued. Let us say I have "success" and "failed" queues in which Server side component has continuously written some data to these queues for clients.
Clients read this data and display it on a UI for end users. Now, I have a situation to purge any message in these queues older than 30 days. Clients would then only be able to see only 30 days of information at any point of time.
I have searched a lot and could see some command line options to purge whole queue but could not find a relevant suggestion.
Any help in the right direction is appreciated. Thanks
I don't think this is possible; looks like you're trying to use RabbitMq as data storage instead of message server.
The only way to understand if a message is "older" than 30, is to process the message, and by doing this you are removing the messagge from the queue.
Best thing to do here is to process the messages and store them in a long term storage; then you can implement a deletion policy to eliminate the older elements.
If you really want to go down this path, RabbitMQ implements TTL at queue level or message level; take a look at this: https://www.rabbitmq.com/ttl.html
[As discussed in comments]
To keep the message in the queue you can try to use a NACK instead of ACK as confirmation; this way RabbitMQ will consider the message undelivered and it will try to deliver it again and again. Remember to create a durable queue (https://www.rabbitmq.com/confirms.html).
You can also check this answer: Rabbitmq Ack or Nack, leaving messages on the queue
I am using WMQ to access an IBM WebSphere MQ on a mainframe - using c#.
We are considering spreading out our service on several machines, and we then need to make sure that two services on two different machines cannot read/get the same MQ message at the same time.
My code for getting messages is this:
var connectionProperties = new Hashtable();
const string transport = MQC.TRANSPORT_MQSERIES_CLIENT;
connectionProperties.Add(MQC.TRANSPORT_PROPERTY, transport);
connectionProperties.Add(MQC.HOST_NAME_PROPERTY, mqServerIP);
connectionProperties.Add(MQC.PORT_PROPERTY, mqServerPort);
connectionProperties.Add(MQC.CHANNEL_PROPERTY, mqChannelName);
_mqManager = new MQQueueManager(mqManagerName, connectionProperties);
var queue = _mqManager.AccessQueue(_queueName, MQC.MQOO_INPUT_SHARED + MQC.MQOO_FAIL_IF_QUIESCING);
var queueMessage = new MQMessage {Format = MQC.MQFMT_STRING};
var queueGetMessageOptions = new MQGetMessageOptions {Options = MQC.MQGMO_WAIT, WaitInterval = 2000};
queue.Get(queueMessage, queueGetMessageOptions);
queue.Close();
_mqManager.Commit();
return queueMessage.ReadString(queueMessage.MessageLength);
Is WebSphere MQ transactional by default, or is there something I need to change in my configuration to enable this?
Or - do I need to ask our mainframe guys to do some of their magic?
Thx
Unless you actively BROWSE the message (ie read it but leave it there with no locks), only one getter will ever be able to 'get' the message. Even without transactionality, MQ will still only deliver the message once... but once delivered its gone
MQ is not transactional 'by default' - you need to get with GMO_SYNCPOINT (MQ transactions) and commit at the connection (MQQueueManager level) if you want transactionality (or integrate with .net transactions is another option)
If you use syncpoint then one getter will get the message, the other will ignore it, but if you subsequently have an issue and rollback, then it is made available to any getter (as you would want). It is this scenario where you might see a message twice, but thats because you aborted the transaction and hence asked for it to be put back to how it was before the get.
I wish I'd found this sooner because the accepted answer is incomplete. MQ provides once and only once delivery of messages as described in the other answer and IBM's documentation. If you have many clients listening on the same queue, MQ will deliver only one copy of the message. This is uncontested.
That said, MQ, or any other async messaging for that matter, must deal with session handling and ambiguous outcomes. The affect of these factors is such that any async messaging application should be designed to gracefully handle dupe messages.
Consider an application putting a message onto a queue. If the PUT call receives a 2009 Connection Broken response, it is unclear whether the connection failed before or after the channel agent received and acted on the API call. The application, having no way to tell the difference, must put the message again to assure it is received. Doing the PUT under syncpoint can result in a 2009 on the COMMIT (or equivalent return code in messaging transports other than MQ) and the app doesn't know if the COMMIT was successful or if the PUT will eventually be rolled back. To be safe it must PUT the message again.
Now consider the partner application receiving the messages. A GET issued outside of syncpoint that reaches the channel agent will permanently remove the message from the queue, even if the channel agent cannot then deliver it. So use of transacted sessions ensures that the message is not lost. But suppose that the message has been received and processed and the COMMIT returns a 2009 Connection Broken. The app has no way to know whether the message was removed during the COMMIT or will be rolled back and delivered again. At the very least the app can avoid losing messages by using transacted sessions to retrieve them, but can not guarantee to never receive a dupe.
This is of course endemic to all async messaging, not just MQ, which is why the JMS specification directly address it. The situation is addressed in all versions but in the JMS 1.1 spec look in section 4.4.13 Duplicate Production of Messages which states:
If a failure occurs between the time a client commits its work on a
Session and the commit method returns, the client cannot determine if
the transaction was committed or rolled back. The same ambiguity
exists when a failure occurs between the non-transactional send of a
PERSISTENT message and the return from the sending method.
It is up to a JMS application to deal with this ambiguity. In some
cases, this may cause a client to produce functionally duplicate
messages.
A message that is redelivered due to session recovery is not
considered a duplicate message.
If it is critical that the application receive one and only one copy of the message, use 2-Phase transactions. The transaction manager and XA protocol will provide very strong (but still not absolute) assurance that only one copy of the message will be processed by the application.
The behavior of the messaging transport in delivering one and only one copy of a given message is a measure of the reliability of the transport. By contrast, the behavior of an application which relies on receipt of one and only one copy of the message is a measure of the reliability of the application.
Any duplicate messages received from an IBM MQ transport are almost certainly going to be due to the application's failure to use XA to account for the ambiguous outcomes inherent in async messaging and not a defect in MQ. Please keep this in mind when the Production version of the application chokes on its first duplicate message.
On a related note, if Disaster Recovery is involved, the app must also gracefully recover from lost messages, or else find a way to violate the laws of relativity.
I have created an IMAP-Server. Now I am searching a way to force the client (in my case an iPhone) to reload a message, because it has changed on the server-side. Does somebody know a way to do this?
The body of a message is not allowed to change in IMAP; the only data item that may be changed for an existing message is the list of flags.
If you want to mimic a change in message body, you effectively have to tell your client that the original message was removed, and a new one created. You achieve the former by sending an EXPUNGE response with the message’s original sequence number, and the latter by sending an EXISTS and/or RECENT response, after which the client would typically issue a FETCH command for the new message.
The IMAP server can't force the IMAP client to do anything.
The closest thing to what you're looking for is IMAP IDLE. With IMAP IDLE, the server can push certain notifications to the client (if the client asked to receive them). The client can then do whatever it wants when it gets those notifications.
I am trying to send a message with attachment using CDO object. When the SMTP Server is available and all the information is correct, the message is correctly sent with the attachment.
However, if the SMTP Server is incorrect the message is not sent (as expected), but it seems to be "stuck" somewhere. I am using:
Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"] = 2
I've searched over the Internet, and found that this option would give a 60 second timeout. But the file I attached to the message is never available.
The test that I've done is to send a message with an attached file and using an invalid SMTP Server. Then, I wait for a few minutes and try to delete the file I had attached. However, when I try do it, I have a permission problem. When I kill the sending email program, I am able to delete the file.
I want to know how to configure the timeout to make sure it gives up sending the message, how I "detach" the file when the message is not sent and how to make the program wait for the message to be sent (I want to send the message and then erase the attached file from the computer. So I need to know when the message was really sent or when it was timedout).
CDO is hopelessly obsolete, you really need to consider switching to System.Net.Mail. The specific problem sounds like a file locking issue. Quacks like a bug in CDO, it would open the attachment to compose the email message but forgets to close the file when the SMTP server balks.
This bug is probably exacerbated by the way .NET deals with COM servers, like CDO. The COM object doesn't get released until the garbage collector runs. Which can take a while, especially when your program doesn't do anything significant after trying to send the email. A workaround for that is calling Marshal.ReleaseComObject() on the CDO object. Tends to not work when you have other CDO interface references in your program, those references tend to be hidden. GC.Collect() + GC.WaitForPendingFinalizers() is the big hammer, after you nulled any object reference.
But, really, use System.Net.Mail.