MailKit : search if custom header exists - mailkit

I have added a custom header in emails, conditionally
and I want using the IMAP/SearchQuery to return only the mails having the header.
Not its value, only to return true/false if the header exists.
Is it possible ? thanks.

According to rfc3501 (the IMAP specification):
HEADER <field-name> <string>
Messages that have a header with the specified field-name (as
defined in [RFC-2822]) and that contains the specified string
in the text of the header (what comes after the colon). If the
string to search is zero-length, this matches all messages that
have a header line with the specified field-name regardless of
the contents.
To make this search in MailKit, what you would do is this:
var results = folder.Search (SearchQuery.Header ("X-Custom-Header", string.Empty));
Edit:
I just discovered a logic bug in MailKit that would decide to send empty strings as ATOMs instead of QSTRING like it should. I've fixed this in git master, but have not made a release yet. I'll probably do that this weekend.

Related

Mailcow sieve script that removes attachments and adds a message to the body

I'm trying to find out how to remove non-whitelisted attachments (by mime type) (f.e. zip, exe, ...)
and append a message about the removed attachments.
I found this: https://superuser.com/a/1502589
And it worked to add a message to the subject.
But I cannot find out how to add a message to the body.
My plan was to use a regex on the attachment mime types and allow f.e.
text/* and application/json etc.
But I cannot find a single example how to change the body.
I'm using mailcow and sieve script (which I'm both new to).
Or is there a better way to "sanitize" emails before the get put into the inbox?
EDIT (2023-02-07) : I found this today:
Extension foreverypart.
Sieve Email Filtering: MIME Part Tests, Iteration, Extraction, Replacement, and Enclosure
https://www.rfc-editor.org/rfc/rfc5703.html \
The "replace" command is defined to allow a MIME part to be replaced
with the text supplied in the command.
Exactly what I try to do.
Now I need to find out how to install the extension and try it out.

An ambiguos part of DKIM specification about header hash

I'm trying to sign email messages according to DKIM specification. I'm reading RFC 6376 and see there relatively straight way to create the signature, but there is a problematic part about DKIM-Signature header's tag b.
As I understand, it's value should be a base64 encoded signature of a hash, that is calculated against selected message headers, including DKIM-Signature, but without a value of the tag b. If it's correct, then I have some trouble understanding RFC here:
The header field MUST be presented to the hash algorithm after the
body of the message rather than with the rest of the header fields
Here the RFC speaks about DKIM-Signature header. The text is from the chapter "3.7. Computing the Message Hashes".
If I understand it correctly, then it means I must calculate a hash of a block, which includes full message body, with the DKIM-Signature header appended to it's end (variant 1). But as I read in other sources, including answers here, it seems (because there's no clear algorithm in other sources) that DKIM-Signature header should be appended to the end of a list of message headers, that are selected for the hashing (variant 2). Then the ambiguity is: which variant is correct?
And finally, after 2 hashes are calculated, should I sign the second hash (hash of headers after disambiguation of a correct variant), as it seems things should work, or should I sign just the list of selected (and canonicalized) headers?
A common sense tells me that variant 2 should be the actual choice, and signature should be applied to the second hash, but I'm in doubts.
The pseudo-code for the signature algorithm in RFC 6376 is wrong. It was corrected in Errata 5252:
body-hash = hash-alg (canon-body, l-param)
data-hash = hash-alg (h-headers, D-SIG)
signature = sig-alg (d-domain, selector, data-hash)
What it means is that you first hash the canonicalized message body up to the length specified in the l parameter and then include this hash in the bh tag of the DKIM-Signature header field. Afterwards, you start a new hash with the header fields as specified in the h tag and canonicalized according to the c tag (an empty string is included for non-existent header fields, so that adding these header fields later on invalidates the DKIM signature) followed by the DKIM-Signature header field which you are about to add without the b tag. The resulting hash is the one you sign. This means that your second variant is the correct one.

Go (lang) parsing an email header and keeping order

I'm using net/mail library in Go, everything is great, however I want to pass in an original email and keep the order of the headers. This is important because the mail servers that pass the message on each add their headers in an order. Without order, its hard to know who received what, when and what headers each server added.
The net/mail library stores the headers in a map, which by definition has no concept of order. Seems a strange choice as header order is based only on order in the email, but it is the case.
Anyone got any suggestions as to how I can retain order the headers were read?
Thanks
The net/mail package uses the net/textproto package to parse the headers
(see ReadMessage()). Specifically, it uses ReadMIMEHeader() for
the headers, which is documented as:
The returned map m maps CanonicalMIMEHeaderKey(key) to a sequence of values
in the same order encountered in the input.
You can view the full source if you want, but the basic process is:
headers = make(map[string][]string)
for {
key, value := readNextHeader()
if key == "" {
return headers // End of headers
}
if headers[key] == nil {
headers[key] = []string{value}
} else {
headers[key] = append(headers[key], value)
}
}
It's true that the original order of the headers as they appeared in the message
is lost, but I'm not aware of any scenario where this truly matters. What
isn't lost is the order of the multi-values headers. The slice ensures they're
in the same order as they appeared in the email.
You can verify this with a simple program which loops over the headers and
compares the values (such as this one in the
Playground).
However, matching Received and Received-SPF headers is a bit more complex,
as:
not every Received header may have a corresponding Received-SPF header;
the Received-SPF header may not appear above the Received header; this is
recommended but not mandated by the RFC (besides, many programs don't
even follow the RFC, so this wouldn't be a guarantee anyway).
So you'll either need to parse the value of the headers and match them based on
that, or use the net/textproto package for more low-level access to the
headers. You can use the source of ReadMIMEHeader() as a starting point.

IMAP - retrieve mail by Yahoo X-YMailISG

Appears for all incoming Yahoo mail, X-YMailISG is an incoming message ID mail can be retrieved by. I'm wondering if this is possible in IMAP or if this field is used for something else entirely?
From RFC 3501, section 6.4.4, you could use SEARCH or UID SEARCH with the HEADER qualifier to look look for the identifier for that message.
Quoted:
HEADER <field-name> <string>
Messages that have a header with the specified field-name (as
defined in [RFC-2822]) and that contains the specified string
in the text of the header (what comes after the colon). If the
string to search is zero-length, this matches all messages that
have a header line with the specified field-name regardless of
the contents.

How can I extract non-standard HTTP headers using Perl's LWP?

I'm working with a web application that sends some non-standard HTTP headers in its response to a login request. The header in question is:
SSO_STATUS: LoginFailed
I tried to extract it with LWP::Response as $response->header('SSO_STATUS') but it does not work. It does work for standard headers such as Set-Cookie, Expires etc.
Is there a way to work with the raw headers?
if you see the documentation of HTTP::Headers, it states that
The header field name spelling is normally canonicalized
including the '_' to '-' translation. There are some application where
this is not appropriate. Prefixing field names with ':' allow you to
force a specific spelling. For example if you really want a header field
name to show up as foo_bar instead of "Foo-Bar", you might set it like
this:
$h->header(":foo_bar" => 1);
These field names are returned with the ':' intact for
$h->header_field_names and the $h->scan callback, but the colons do
not show in $h->as_string.
See this thread on Perlmonks.
You need to access the value of the header field as $response->header('SSO-STATUS').
The syntax for setting fields with underscores in names:
$response->header(':SSO_STATUS' => 'foo');