Every email admin most likely has seen one way or another of tagging external emails. While this sounds like a very easy task there are some pitfalls to avoid. This blog article consists of two parts. Part 1 one will cover the tagging of the subject line while Part 2 will cover of disclaimers.
Lets start by tagging the subject line with [EXTERNAL EMAIL] like in the following example:
The easiest way would be to create an incoming content filter like the following to get this done:
Apply the filter to you default incoming mail policy and you would be all set. Now we have a set of users which will very soon complain about one of the following limitations and requirements:
a) make sure that the external tagging in the subject is only added once when the message is getting a lot of replies
b) make sure that the external is not applied to some other domains and some "special" senders like external hosted applications
c) make sure adding the external tag does not break incoming secured messages like S/MIME
d) make sure the tagging will not be applied to all of our other email domains of our parent company
Since the GUI based content filters in the Cisco Ironport's in year 2020 still do not support more complex or conditions there is only the possibility to use a CLI based message filters to achieve this goal.
For those of you not familiar with the CLI interface, don't be scared, you can not break more things then by using the traditional GUI but it gives you some advantages. I personally like to use message filters over content filters when they need to do either directory lockups or have many lines of code and require complex lifting.
I will go ahead and show first a very easy version of a CLI based message filter which does the same than the GUI based version above will update the filter by adding more features to address requirements as we go.
First of all you want to make it is still easy for the normal admin to be able to maintain the system. Instead of all admins becoming CLI gurus we will leverage some static templates and dictionaries which can be managed via the GUI by any admin. So only major new features will require edits of this filter on CLI.
A very basic filter to match the GUI version above, with one exception. Since it is CLI based it is applied to all incoming and outgoing traffic by default. To avoid this, it is highly recommended to always include a query for the inbound listener interface. This name might be different in your setup and should be checked in the GUI under Network \ Listeners first. It is best practice to always include a log-entry for every message filter so you can easily see if your filter was applied using Message Tracking or by checking the mail log files. The matching CLI filters looks like this:
CLITagExtSubBasicv1: if recv-listener == "InboundInterface" {
if mail-from != "owndomain.com" {
insert-header("Subject", "[EXTERNAL EMAIL] $Subject");
log-entry("--CLITagExtSubBasic--");
}
}
If you never created a CLI based message filter then do the following. Connect to your Ironport using SSH, login with your username and password. Type "filters" and select the add new filter option. Type or copy above message filter and at the end press return and enter "." on an empty line. This will check your filter for errors and will save it.
The next requirement was to make sure the filter only gets applied one time, for messages which have multiple replies. Otherwise the filter would always add the tag to the subject and it would easily become unreadable. There are multiple ways on how to do this. One way would be to check for the presence of the [EXTERNAL EMAIL] tag in the subject, another way would be to insert an X-header into the message when the tag gets first time added and check for that presence every time.
I no longer remember why we have ended up with the current option but based on the fact that 100% of the subjects are correctly modified and no more complains about double tagging have been reported this option seems to work very well. The modified code would now look like this :
CLITagExtSubBasicv2: if recv-listener == "InboundInterface" {
if mail-from != "owndomain.com" {
if subject != "EXTERNAL EMAIL" {
insert-header("Subject", "[EXTERNAL EMAIL] $Subject");
log-entry("--CLITagExtSubBasic--");
}
}
}
For the next requirement of allowing exceptions there are again multiple ways. You can start by adding multiple check ins the mail-from line above to allow for some exception but this becomes very quickly unmanageable. A better way is to include a lookup into a whitelist, which will be implemented as a dictionary.
Just go into the GUI section Mail Polices \ Dictionary and a new dictionary and give it an appropriate name like WhiteListExtSubTagging. Deselect the two advanced matching options and you might want to add a dummy email address for testing purposes like your personal gmail account. Don't forget to submit and commit the dictionary.
The result should then look like this:
Once the dictionary is created you can extend the message filter to allow exceptions from the tagging of the subject line based on dictionary entries. Please make sure you add the FROM address of sender emails to be excluded from subject line tagging
CLITagExtSubBasicv3: if recv-listener == "InboundInterface" {
if NOT (mail-from-dictionary-match("WhiteListExtSubTagging", 1)) {
if mail-from != "owndomain.com" {
if subject != "EXTERNAL EMAIL" {
insert-header("Subject", "[EXTERNAL EMAIL] $Subject");
log-entry("--CLITagExtSubBasic--");
}
}
}
}
This filter worked fine for a while but with a bigger deployment of S/MIME in Europe and the US government there have been reported cases where those emails just got corrupted and could no longer be opened by end users. Analyzing did show that inserting an X-header and modifying the subject did break our incoming S/MIME message envelope so we had to come up with a way on how to detect such cases and exclude them from our filter. The easiest way we have found was to add a complete section for S/MIME detection and use a different tag to alert users.
CLITagExtSubBasicv4: if recv-listener == "InboundInterface" {
if NOT (mail-from-dictionary-match("WhiteListExtSubTagging", 1)) {
if mail-from != "owndomain.com" {
if subject != "EXTERNAL EMAIL" {
if (NOT (attachment-filename== "smime.p7s")) OR (attachment-filename== "smime.p7m")) {
insert-header("Subject", "[EXTERNAL EMAIL] $Subject");
log-entry("--CLITagExtSubBasic--");
}
if (NOT (attachment-filename== "smime.p7s")) OR (attachment-filename== "smime.p7m")) {
insert-header("Subject", "[EXTERNAL SMIME EMAIL] $Subject");
log-entry("--CLITagExtSubBasicSMIME--");
}
}
}
}
}
From now on we just add a tag in the subject line so we can with a later filters take special care so we are not breaking any S/MIME signed or encrypted messages. Company's are growing and you will likely end up with many more email domains you need to manage. Again you might want to avoid editing those filters to often, so to address the last requirement we will add yet another dictionary as described above, this time called something like OurGroupDomains with the same attributes.
We will edit the filter one more time and will replace the part where we look for incoming email from our domain as below:
CLITagExtSubBasicv5: if recv-listener == "InboundInterface" {
if NOT (mail-from-dictionary-match("WhiteListExtSubTagging", 1)) {
if NOT (mail-from-dictionary-match("OurGroupDomains", 1)) {
if subject != "EXTERNAL EMAIL" {
if (NOT (attachment-filename== "smime.p7s")) OR (attachment-filename== "smime.p7m")) {
insert-header("Subject", "[EXTERNAL EMAIL] $Subject");
log-entry("--CLITagExtSubBasic--");
}
if (NOT (attachment-filename== "smime.p7s")) OR (attachment-filename== "smime.p7m")) {
insert-header("Subject", "[EXTERNAL SMIME EMAIL] $Subject");
log-entry("--CLITagExtSubBasicSMIME--");
}
}
}
}
}
This completes the first part of the external tagging series, the second part will follow soon on how to include more fancy disclaimer messages.
Another task completed in the life of an email admin.
Hi, I am curious about the last few lines of code, in relation to the S/MIME. Are both line entries supposed to be if (NOT... I am thinking one should be if(NOT and the other a if ?