Determining the uid of a message appended to a mailbox via IMAP - imap

How do I determine the UID of a message which is added via APPEND to a mailbox? Through STATUS I can get a prediction of the next value beforehand and I can SEARCH afterwards, but relying on these introduces a race condition as other messages might have been added between these commands.

If you IMAP server supports UIDPLUS, you will always get an APPENDUID response. This will contain the UID and the validity period for the UID.
Sample syntax from RFC 4315:
S: A003 OK [APPENDUID 38505 3955] APPEND completed
If your mailserver doesnt support UIDPLUS, you will have to do a FETCH for the UID, once your append operation is finished. If you are sure that no message was added after the append, go look for the last message in the FETCH response.
FETCH 1:* (UID)
If you are worried about other messages getting added, you can save an IMAP header like Message-ID before the APPEND and later use it in the FETCH operation.

Related

What causes a "NO UID SEARCH State error"

I have a script that connects via TCP/Sockets, Authenticates SSL, and then checks if the response from stream returns "OK".
It then sends a UID search command:
{tag} UID SEARCH (UNDELETED) (SENTSINCE "{RFC2060 Format Date}")
I then follow that with another OK check aswell as a * SEARCH stream response check.
When both of those are not true, I always end up with this as a result from the stream: xm005 NO UID SEARCH State error
Im not certain but is it possible this returns if the email has no UNDELETED inbox or something?
This seems to occur all the time on one of my chinese friends specific accounts on yeah.net (163-China related email service).
When I login to it with Windows 10's Mail App, I can see it has inboxes in CHINESE. Is it possible something to do with that is causing this issue?
I'm essentially wanting to search for every email within the sent-since date that has not been deleted, perhaps (UNDELETED) isn't a global declaration and is an actual inbox or something?
According to IMAPv4.1's RFC:
UNDELETED
Messages that do not have the \Deleted flag set.
So maybe its not to do with Inbox's? regardless its pretty odd that both emails this occurs on have Chinese Inbox's yet my English-Only one works splendid.
I removed (UNDELETED) and attempted running, and the same issue occurs, so it's not that.
The "state" in the error message could mean "your state does not include a mailbox". Make sure to issue a SELECT command before UID SEARCH.

how to figure out all messages with a specific groupId has been read from the queue in SQS?

Here is my requirement: I receive a request to validate some data/records. Records would be sent to the SQS queue per each request for further processing by another service/component. The message structure looks like this:
messageId: //a unique message id
requestId: //request id common between all messages/records for that request
record_body: {//key-value pairs}
Everything works fine. Now I want to figure out when all messages with the same request id have been read from the queue (I.e. there is no more message for that request id).
The idea that I have is to write each message/record to the database upon each read and then have another scheduled service that can be triggered (by cloudwatch) to check the number of records for each request and finally update the status of the request to complete if the number of records in the database are equal to the number of records in the original request.
I just want to share this to see if anybody else had this kind of requirement and how they approached it!
How about this ?
Include the number of requests and current request to the queue. Make sure the request goes to the queue in the same order.
Example - You have 4 requests for requestId - abc
You will send each request with values included (1:4) (2:4) (3:4) (4:4) in the order to the queue.
This way when you are reading from the queue you will read (4:4) last and you will know you have processed all the 4.
Another way to do is include total number of requests in the message in every message and while processing each message check whether it matches the original one as you have total in your message now. (by querying the database).

Get Relative message number from UID in IMAP?

In IMAP it's pretty straightforward to get the UID for a single message if you happen to have a relative message number:
FETCH 1 (UID)
But suppose you had a UID and later wanted to determine the relative message number for just that message? Does IMAP provide a way to do that?
I'm not seeing anything especially obvious in the spec that would allow you to get the relative message number for a single message. I could do
UID FETCH 1:* (UID)
and then parse and search through the results to find it, but that seems like overkill (not to mention exponentially slow).
Pretty simple:
tag UID FETCH <uid> (UID)
The response will include the message number, not in the fetch information but as the initial part of the response
tag <messagenumber> FETCH (UID <uid>)

IMAP FETCH Subject

Using IMAP via telnet, I want to be able to extract the subject from the specific given email. Now I know that the fetch command is responsible for getting data from an email.
My question is, how do I get the subject header specifically, without using a call to BODY[HEADER.FIELDS (SUBJECT)] (which will, in the eyes of the server, 'open the email' and thus set the /seen flag, which is what I don't want to occur)?
I understand FETCH FULL returns the full header, which contains the subject but it's a nightmare to parse through and could be riddled with unseen pitfalls if I manually parse it. How would I get the server to give me just the subject from the header?
I discovered the answer:
BODY.PEEK[HEADER.FIELDS (SUBJECT)]
.PEEK tells it not open it (so /seen isn't set).
Besides BODY.PEEK, you could fetch ENVELOPE, which gives you a parsed summary of much of the message metadata.
"a1 FETCH 1:* (FLAGS BODY[HEADER.FIELDS (SUBJECT DATE FROM)])\r\n"

Is this a proper implementation of PUT idempotency and what should the response be?

The way I have understood idempotency thus far is basically: If I send 10 identical PUTs to a server the resulting additional resources created will be identical to if I had sent a single PUT statement.
What I take this to mean is that the following implementation would adhere to this:
[AcceptVerbs(HttpVerbs.Put)]
ContentResult User(){
//parse XML that was sent to get User info
//User has an e-mail address which is unique to the system
//create a new user in the system only if one for this e-mail address does not exist
return Content(something, "text/xml");
}
There now if I sent 10 PUTs with XML for User data and they all contain the same e-mail address, only one user will be created.
However, what if they send 10 requests (for whatever reason) and they are all different, but the e-mail is the same. If the first request doesn't make it through then the data of the 2nd request will be used to create the user, and the following 8 requests will be ignored. Is there a flaw here? Or should I literally only ignore requests that are explicitly identical in every way and instead send back an error saying the user already exists if they use the same e-mail address?
Also, what kind of response should be sent from a such PUT statement? Info about the user? Maybe an ID to manipulate them with other API calls? Or perhaps it should just say "success" or "fail: [error details]"?
Your question doesn't reveal the URL where the PUT request is sent to. This is actually very important as it is not the email address within the XML data that dictates whether a new resource is created or an old one updated but the URL that you are sending the request to.
So, if you send PUT to /users/jonh.doe#foo.com/ it either creates the user john.doe#foo.com or updates it if it was already in the system.
Similaraly, if you send PUT to /users/123/ (using id instead of email) it will create or update user 123. However, in this case if the email has to be unique and somebody sends PUT /users/456/ and within that XML is the same email as what the user 123 already has, you have to respond with 409 Conflict.
If the user already exists with the same email address, then the 2nd and subsequent PUT operations should update the data for that resource. The success or failure should be communicated in the status code. If the update succeeds, respond with "200 OK", or "204 No Content"; you can return some information, but don't expect caches to store it as if it were the new representation you would obtain from a GET. If you do not intend for that resource to ever accept a PUT operation other than the first one, then respond instead with "405 Method Not Allowed", with an explanation in the response body. Use "409 Conflict" (again, with an explanation in the response body) if the submitted representation might replace the resource, but can't because it's particular fields cannot be reconciled with the existing state.

Resources