RFC 5703
Sieve Email Filtering: MIME Part Tests, Iteration, Extraction, Replacement, and Enclosure
Sieve Email Filtering: MIME Part Tests, Iteration, Extraction, Replacement, and Enclosure ๐
Okay bestie, this one is RFC 5703 and it's giving email filtering glow-up ๐ Written by T. Hansen (AT&T Laboratories) and C. Daboo (Apple Inc.), it's on the Standards Track and dated October 2009 ๐ Its title block doesn't list anything it obsoletes or updates, so no drama there ๐ธ
Abstract โจ
The big idea is that this doc adds new Sieve powers so your filters can poke at and manipulate the MIME body parts inside an email message ๐ฌ Main character energy for your inbox ๐
Status of This Memo ๐
This is an Internet standards track protocol for the Internet community, and they're literally asking for discussion and suggestions for improvements ๐ฆ If you want the current standardization state and status, check STD 1, the "Internet Official Protocol Standards" ๐ Distribution of this memo is unlimited ๐
Copyright Notice ยฉ๏ธ
Copyright (c) 2009 IETF Trust and the persons identified as the document authors. All rights reserved. ๐ซถ
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they stand on the publication date. Please read these carefully, because they spell out your rights and restrictions ๐ Code Components pulled out of this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty as described in the BSD License โ๏ธ
Heads up: this document may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. The people controlling the copyright in some of that material may not have granted the IETF Trust the right to allow modifications outside the IETF Standards Process. Without an adequate license from those copyright holders, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process. The only exceptions are formatting it for publication as an RFC or translating it into languages other than English ๐ซ
Table of Contents ๐
1. Introduction ....................................................2
2. Conventions Used in This Document ...............................3
3. Sieve Loops: Actions "foreverypart" and "break" .................3
4. Changes to Sieve Tests ..........................................4
4.1. Test "header" ..............................................4
4.2. Test "address" .............................................7
4.3. Test "exists" ..............................................8
5. Action "replace" ................................................8
6. Action "enclose" ...............................................10
7. Action "extracttext" ...........................................11
8. Sieve Capability Strings .......................................11
9. Examples .......................................................12
9.1. Example 1 .................................................12
9.2. Example 2 .................................................12
9.3. Example 3 .................................................13
10. Acknowledgements ..............................................13
11. Security Considerations .......................................14
12. IANA Considerations ...........................................14
12.1. foreverypart capability ..................................15
12.2. mime capability ..........................................15
12.3. replace capability .......................................15
12.4. enclose capability .......................................16
12.5. extracttext capability ...................................16
13. References ....................................................16
13.1. Normative References .....................................16
13.2. Informative References ...................................17
1. Introduction ๐ท
MIME messages ([RFC2045]) are often complex objects, consisting of many parts and sub-parts ๐งฉ This Sieve ([RFC5228]) extension is the toolkit for it. It defines mechanisms for performing tests on MIME body parts, looping through the MIME body parts, extracting information from a MIME body part, changing the contents of a MIME body part, and enclosing the entire message within a wrapper ๐
2. Conventions Used in This Document ๐
Conventions for notations are as in [RFC5228], Section 1.1 ๐
Okay, the BCP 14 key words are the important bit ๐ฅ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119] ๐ซถ
3. Sieve Loops: Actions "foreverypart" and "break" ๐
Plain Sieve has no looping mechanism, which is kind of a vibe check when messages can have multiple parts ๐ญ So to support filters that apply to any and all parts, this doc introduces a new control command called "foreverypart" โจ It's an iterator that walks through every MIME part of a message, including nested parts, depth first, and applies the commands in the specified block to each one ๐ง
Here's how it goes: the iterator starts with the first MIME part as its current context and executes a command block (Sieve commands enclosed by {...}). When that block finishes, the iterator advances to the next MIME part as its current context and runs the same command block again ๐
The iterator can be terminated early by a new Sieve control command called "break" ๐
Here's the usage:
Usage: foreverypart [":name" string] block
Usage: break [":name" string];
Loops can nest, which is so iconic ๐ "foreverypart" commands can be nested inside other "foreverypart" commands. When that happens, the nested "foreverypart" iterates over the MIME parts contained within the MIME part currently being targeted by the nearest enclosing "foreverypart" command. So the inner loop only works on the children of the bodypart the outer loop is currently accessing ๐ช If that MIME part is a terminal MIME part (meaning it doesn't contain other MIME parts), then the nested "foreverypart" loop is simply ignored ๐
Limits are a real thing here. Sieve implementations MAY limit the number of nested loops that occur within one another. However, they MUST support at least one nested loop inside another loop ๐
Now for names. If a name is given to a "break" command, it terminates the closest enclosing loop with the identical matching name โ๏ธ If a nested "foreverypart" has the same name as a "foreverypart" at an outer level, the outer level name gets hidden ๐ซฅ And it's an error if there's no enclosing loop with that name ๐
If there's no name in a "break" command (so the ":name" parameter is omitted), the break command just terminates the closest enclosing loop ๐ฆ
4. Changes to Sieve Tests ๐งช
This spec extends the base Sieve "header", "address", and "exists" tests so they can target a specific MIME part, or all MIME parts in the enclosing scope ๐ฏ
4.1. Test "header"
okay bestie, the "header" test just got a glow-up ๐ โจ It picks up two new tagged arguments, ":mime" and ":anychild", plus their own options. ๐
Usage:
header [":mime"] [":anychild"] [MIMEOPTS]
[COMPARATOR] [MATCH-TYPE]
<header-names: string-list> <key-list: string-list>
The definition of [MIMEOPTS] is:
Syntax: ":type" / ":subtype" / ":contenttype" /
":param" <param-list: string-list>
So when you add ":mime", the test parses the MIME header lines in the message so you can test specific bits of them ๐ฆ The ":anychild" argument only works if ":mime" is there too, and it just changes how ":mime" behaves. Using ":anychild" without ":mime" is an error, so don't do that ๐
Here's how the test looks at your message depending on where you use it:
- Outside a
foreverypartloop, without ":anychild", it only checks the outer top-level [RFC5322] headers. ๐ฌ - Inside a
foreverypartloop, without ":anychild", it checks the headers for the current MIME part from the loop. ๐ง - Outside a
foreverypartloop, with ":anychild", it checks every MIME body part and returns true if any one of them passes. ๐ - Inside a
foreverypartloop, with ":anychild", it checks the current MIME part and all its nested MIME body parts, and returns true if any of them passes. ๐
With ":mime", the test can poke at certain structured MIME headers in detail. Implementations SHOULD support desegmentation, decoding, and charset translation of parameter values encoded according to [RFC2231] as part of this test. ๐ Also, [RFC2047] explains how [RFC5322] headers can be encoded in different ways. That encoding isn't strictly allowed in MIME parameters, but honestly, lots of email implementations use it anyway ๐ So Sieve implementations MAY decode [RFC2047]-encoded words in parameter values as part of this test.
These options are available:
:type: For a "Content-Type" MIME header field, it parses and tests the MIME type from the header. For a "Content-Disposition" MIME header field, it parses and tests the disposition from the header. For other MIME headers, it uses a blank string for the test. ๐:subtype: For a "Content-Type" MIME header field, it parses and tests the MIME subtype from the header. For a "Content-Disposition" MIME header field, it uses a blank string for the test. For other MIME headers, it also uses a blank string for the test. ๐ธ:contenttype: For a "Content-Type" MIME header field, it parses and tests the combined MIME type and subtype from the header. For a "Content-Disposition" MIME header field, it behaves the same as the:typeoption. For other MIME headers, it uses a blank string for the test. ๐ซถ:param: Parses the header looking for MIME parameters. The string-list you pass in names the parameters to test. If any one named parameter value matches any of the test string values, the test returns true. โจ
When the ":count" option from [RFC5231] is used, this is what happens:
a. For ":type", ":subtype", or ":contenttype", it returns a count of how many headers parsed successfully. ๐ข
b. For ":param", it returns a count of how many parameters with the given name were found. ๐งฎ
Example:
require ["mime", "fileinto"];
if header :mime :type "Content-Type" "image"
{
fileinto "INBOX.images";
}
In this example, any message with a MIME image type part at the top level gets saved to the mailbox "INBOX.images". ๐ธ
Example:
require ["mime", "fileinto"];
if header :mime :anychild :contenttype
"Content-Type" "text/html"
{
fileinto "INBOX.html";
}
In this example, any message with any MIME part that has a content-type of "text/html" gets saved to the mailbox "INBOX.html". ๐
Example:
require ["mime", "foreverypart", "fileinto"];
foreverypart
{
if allof (
header :mime :param "filename" :contains
"Content-Disposition" "important",
header :mime :subtype "Content-Type" "pdf",
size :over "100K")
{
fileinto "INBOX.important";
break;
}
}
In this example, any message with a MIME part whose content-disposition has a filename parameter containing the text "important", a content-subtype of "pdf", and a size over 100 Kb gets saved to the mailbox "INBOX.important". ๐ญ๐ฅ
4.2. Test "address"
The "address" test gets the same ":mime" and ":anychild" upgrade, with its own options ๐ฆ
Usage:
address [":mime"] [":anychild"] [COMPARATOR]
[ADDRESS-PART] [MATCH-TYPE]
<header-list: string-list> <key-list: string-list>
When ":mime" is in the "address" test, it parses the MIME header lines as if they were standard address header lines in a message. That way you can test specific elements, bestie ๐ฌ
The ":anychild" argument and how it plays with the "foreverypart" iterator work exactly the same as in the extended "header" test in Section 4.1. So here's the breakdown:
- Using "address" with both ":mime" and ":anychild" left out is the test defined in [RFC5228]. It will only operate on top-level header fields, whether or not it's inside "foreverypart". ๐
- Using "address" with ":mime" and no ":anychild" operates on the current MIME part only. If you're outside "foreverypart", it operates on the top-level header fields. ๐ธ
- Using "address" with ":mime" and ":anychild" operates on the current MIME part and all of its descendants. ๐
Example:
require ["mime", "fileinto"];
if address :mime :is :all "content-from" "tim@example.com"
{
fileinto "INBOX.part-from-tim";
}
In this example, any message with a MIME Content-From header at the top level that matches the text "tim@example.com" gets saved to the mailbox "INBOX.part-from-tim". ๐
4.3. Test "exists"
The "exists" test also gets the new ":mime" and ":anychild" tagged arguments, along with their options ๐ง
Usage:
exists [":mime"] [":anychild"] <header-names: string-list>
When ":mime" is in the "exists" test, the test checks whether MIME headers exist in MIME parts. It's giving main character energy ๐
The ":anychild" argument and its interaction with "foreverypart" are the same as in the extended "header" test Section 4.1. So:
- Using "exists" with both ":mime" and ":anychild" left out is the test defined in [RFC5228]. It will only operate on top-level header fields, whether or not it's inside "foreverypart". ๐
- Using "exists" with ":mime" and no ":anychild" operates on the current MIME part only. If you're outside "foreverypart", it operates on the top-level header fields. ๐ซถ
- Using "exists" with ":mime" and ":anychild" operates on the current MIME part and all of its descendants. ๐
Example:
require ["mime", "fileinto"];
if exists :mime :anychild "content-md5"
{
fileinto "INBOX.md5";
}
In this example, any message with a MIME Content-MD5 header in any MIME part gets saved to the mailbox "INBOX.md5". ๐ฅ
5. Action "replace"
Okay, the "replace" action is where things get spicy ๐ถ๏ธ๐ It lets you swap a MIME part out for text you supply in the command.
Usage:
replace [":mime"] [":subject" string] [":from" string]
<replacement: string>
The "replace" command is defined so a MIME part can be replaced with the text you give it in the command ๐ฆ
When you use it inside a "foreverypart" iterator, the MIME part to replace is the "current" MIME part. If the current MIME context is a multipart MIME part, the whole multipart part gets replaced. That changes the message structure, because it wipes out all of the children of the multipart part ๐ฑ (Replacing a non-multipart MIME part inside a "foreverypart" loop doesn't change the overall message structure, so you're safe there ๐ซถ) If the MIME structure does change, the change takes effect right away. The "foreverypart" iterator that's running doesn't go into body parts that no longer exist, and any later "foreverypart" iterators use the new message structure ๐
When you use it outside a "foreverypart" loop, the MIME part to replace is the entire message ๐
If you don't specify ":mime", the replacement string is a text/plain part in UTF-8 [RFC3629] ๐ธ
If you do specify ":mime", the replacement string is actually a MIME entity as defined in [RFC2045], Section 2.4. That includes both the MIME headers and the content ๐
If the entire message is being replaced, the optional ":subject" parameter sets a subject line on the message that gets generated. You can use UTF-8 characters in the string argument, but implementations MUST convert the string to [RFC2047]-encoded words if and only if non-ASCII characters are present. If you use the ":subject" parameter, implementations MUST preserve any previous Subject header as an Original-Subject header. Implementations MUST also preserve all other header fields from the original message, except for the ones relating to the MIME structure being replaced. ๐ซถ
Also, if the entire message is being replaced, the optional ":from" parameter can be used to show the message is no longer as created by the original author. It sets an alternate address for the From field of the generated message. The string must specify a valid [RFC5322] mailbox-list. Implementations SHOULD check the syntax and generate an error when a syntactically invalid ":from" parameter is specified. Implementations MAY also impose restrictions on which addresses can go in a ":from" parameter. It's suggested that values failing that validity check simply get ignored, instead of making the "replace" action fail ๐ If the From header is changed, implementations MUST preserve the previous From header as an Original-From header. ๐
Implementations that support the "editheader" extension [RFC5293] MUST ensure that any Original-Subject or Orignal-From headers added by the system cannot be modified or removed. Implementations MAY prevent Original-Subject and Orignal-From headers from being added through the "editheader" extension. ๐
If ":mime" is specified and either ":subject" or ":from" is specified too, the ":subject" or ":from" parameter MUST be ignored. This SHOULD be flagged as a compilation error. ๐จ
6. Action "enclose" ๐
Usage:
enclose <:subject string> <:headers string-list> string
okay so this is the action that wraps your WHOLE message up like a gift ๐ A new Sieve action command lets you enclose an entire message as an attachment inside a brand new message. After the enclosure happens, any later actions that touch the message header or content, plus tests that look at the MIME structure or read MIME header fields, use the new message instead of the original one. So if you're gonna use a replace action or any similar actions, do them BEFORE enclose ๐ ngl this order thing is so important.
If a script runs multiple enclose actions, the message gets enclosed multiple times ๐ช Like, nesting dolls, iconic. If your script wants to pick between different enclosures, or wants to put the enclosure off until the very end of the script, it can use variables with the right tests instead ([RFC5229]) โจ
This action does not affect messages that get forwarded through a redirect action ๐ฆ
Here's the breakdown: the original message turns into a multipart/mixed message with two parts. Part one is a text/plain portion whose body is the string argument. Part two is a message/rfc822 portion holding the original message, enclosed ๐
The Content-Type: header field becomes multipart/mixed. The optional Subject: header is set by the :subject argument. If that's not there, the subject gets taken from the enclosed message. Any headers listed in :headers get copied from the old message into the new one. And if :headers doesn't specify them, the Date: and From: headers should be synthesized to show the current date and the user who's running the Sieve action ๐ธ
7. Action "extracttext" ๐ง
Usage:
extracttext [MODIFIER] [":first" number] <varname: string>
The extracttext action is used inside a foreverypart loop, and it stores text into a variable as defined by [RFC5229] ๐ Servers MUST support transcoding any textual body part into UTF-8 for use with this action ๐ซถ That means decoding any transfer encoding AND transcoding from the indicated character set into UTF-8. It stores at most :first characters of the transcoded content of the current MIME body part in the variable named by varname. If :first isn't there, the WHOLE content of the current MIME body part gets stored. Either way, the stored data MAY be truncated to fit an implementation-specific limit on variable length and/or on MIME body part length. And if the transfer encoding or character set is unrecognized by the implementation, or recognized but invalid, you get an empty string ๐
If extracttext is used OUTSIDE a foreverypart loop, the variable named by varname just gets set to the empty string. This SHOULD be flagged as a compilation error ๐ฉ
Modifiers get applied to the extracted text before it's stored in the variable โจ
8. Sieve Capability Strings ๐
A Sieve implementation that defines the foreverypart and break actions will advertise the capability string foreverypart ๐ง
A Sieve implementation that defines the :mime and :anychild tagged arguments for the header, address, and exists commands will advertise the capability string mime ๐
A Sieve implementation that defines the replace action will advertise the capability string replace ๐
A Sieve implementation that defines the enclose action will advertise the capability string enclose ๐
A Sieve implementation that defines the extracttext action will advertise the capability string extracttext. Heads up, though: to actually be useful, extracttext ALSO needs the "variables" [RFC5229] and foreverypart capabilities ๐ซ
9. Examples ๐
9.1. Example 1
Let's look at a Sieve script that replaces some of the Windows executable attachments in a message ๐ (The real list of executable types and extensions is way longer and keeps changing, so the tests here are just an example.) A script like this might look something like:
require [ "foreverypart", "mime", "replace" ];
foreverypart
{
if anyof (
header :mime :contenttype :is
"Content-Type" "application/exe",
header :mime :param "filename"
:matches ["Content-Type", "Content-Disposition"] "*.com" )
{
replace "Executable attachment removed by user filter";
}
}
9.2. Example 2
Next, a Sieve script that warns the user about some of the executable attachment types โ ๏ธ (Same deal: the real list is longer and changing, so these tests are only an example.) A script like this might look like:
require [ "foreverypart", "mime", "enclose" ];
foreverypart
{
if header :mime :param "filename"
:matches ["Content-Type", "Content-Disposition"]
["*.com", "*.exe", "*.vbs", "*.scr",
"*.pif", "*.hta", "*.bat", "*.zip" ]
{
# these attachment types are executable
enclose :subject "Warning" :text
WARNING! The enclosed message contains executable attachments.
These attachment types may contain a computer virus program
that can infect your computer and potentially damage your data.
Before clicking on these message attachments, you should verify
with the sender that this message was sent by them and not a
computer virus.
.
;
break;
}
}
9.3. Example 3
Here's a Sieve script that pulls the subject and text out of messages from the boss ๐
require ["mime", "variables", "extracttext"];
if header :contains "from" "boss@example.org"
{
# :matches is used to get the value of the Subject header
if header :matches "Subject" "*"
{
set "subject" "${1}";
}
# extract the first 100 characters of the first text/* part
foreverypart
{
if header :mime :type :is "Content-Type" "text"
{
extracttext :first 100 "msgcontent";
break;
}
}
# if it's not a 'for your information' message
if not header :contains "subject" "FYI:"
{
# do something using ${subject} and ${msgcontent}
# such as sending a notification using a
# notification extension
}
}
10. Acknowledgements ๐ซถ
Big thank-yous to the members of the MTA Filters Working Group, especially Ned Freed, Kjetil Torgrim Homme, Mark Mallett, Alexey Melnikov, Aaron Stone, and Nigel Swinson ๐ Your comments were so helpful!
11. Security Considerations ๐
Heads up, this section is SERIOUS ๐ค
The enclose action creates an entirely new message, unlike just redirecting or forwarding the existing one ๐จ So any site policies that apply to message submission SHOULD be enforced.
The looping specification here makes it easier to get at information about the message contents, which you could also get through other Sieve tests. This is not believed to raise any additional security issues beyond those for the Sieve "envelope" and "body" [RFC5173] tests ๐
Any change in message content may interfere with digital signature mechanisms that include that content in the signed material ๐๏ธ In particular, using replace makes direct changes to the body content, and that will affect the body hash in DomainKeys Identified Mail (DKIM) signatures [RFC4871], or the message signature used for Secure MIME (S/MIME) [RFC3851], Pretty Good Privacy (PGP) [RFC1991], or OpenPGP [RFC4880].
It is not possible to examine the MIME structure of decrypted content in a multipart/encrypted MIME part ๐
When enclose is used on a message containing a multipart/signed MIME part, the Sieve implementation MUST ensure that the original message is copied octet-for-octet, so the digital signature stays valid ๐
The system MUST be sized and restricted so that even malicious use of MIME part matching cannot deny service to other users of the host system ๐ก๏ธ
All of the security considerations given in the base Sieve specification also apply to these extensions ๐
12. IANA Considerations ๐
The Original-Subject and Original-From headers have been registered in the Permanent Message Header Fields registry โจ
The templates below specify the IANA registrations of the Sieve extensions in this document. This information has been added to the IANA registry of Sieve Extensions (currently found at http://www.iana.org) ๐ฆ
12.1. foreverypart capability
To: iana@iana.org
Subject: Registration of new Sieve extension
Capability name: foreverypart
Description: adds the "foreverypart" and "break" actions for
iterating through MIME parts of a message.
RFC number: RFC 5703
Contact address: The Sieve discussion list
<ietf-mta-filters@imc.org>.
12.2. mime capability
To: iana@iana.org
Subject: Registration of new Sieve extension
Capability name: mime
Description: adds the ":mime" and ":anychild" tagged arguments to the
"header", "address", and "exists" tests. Adds the ":type",
":subtype", ":contenttype", and ":param" options when ":mime" is used
with the "header" test.
RFC number: RFC 5703
Contact address: The Sieve discussion list
<ietf-mta-filters@imc.org>.
12.3. replace capability
To: iana@iana.org
Subject: Registration of new Sieve extension
Capability name: replace
Description: adds the "replace" action for replacing a MIME body part
of a message.
RFC number: RFC 5703
Contact address: The Sieve discussion list
<ietf-mta-filters@imc.org>.
12.4. enclose capability
To: iana@iana.org
Subject: Registration of new Sieve extension
Capability name: enclose
Description: adds the "enclose" action for enclosing a message with a
wrapper.
RFC number: RFC 5703
Contact address: The Sieve discussion list
<ietf-mta-filters@imc.org>.
12.5. extracttext capability
To: iana@iana.org
Subject: Registration of new Sieve extension
Capability name: extracttext
Description: adds the "extracttext" action for extracting text from a
MIME body part.
RFC number: RFC 5703
Contact address: The Sieve discussion list
<ietf-mta-filters@imc.org>.
13. References ๐
13.1. Normative References
[RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
Extensions (MIME) Part One: Format of Internet Message
Bodies", RFC 2045, November 1996.
[RFC2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions)
Part Three: Message Header Extensions for Non-ASCII Text",
RFC 2047, November 1996.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2231] Freed, N. and K. Moore, "MIME Parameter Value and Encoded
Word Extensions:
Character Sets, Languages, and Continuations", RFC 2231,
November 1997.
[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
10646", STD 63, RFC 3629, November 2003.
[RFC5173] Degener, J. and P. Guenther, "Sieve Email Filtering: Body
Extension", RFC 5173, April 2008.
[RFC5228] Guenther, P. and T. Showalter, "Sieve: An Email Filtering
Language", RFC 5228, January 2008.
[RFC5229] Homme, K., "Sieve Email Filtering: Variables Extension",
RFC 5229, January 2008.
[RFC5231] Segmuller, W. and B. Leiba, "Sieve Email Filtering:
Relational Extension", RFC 5231, January 2008.
[RFC5293] Degener, J. and P. Guenther, "Sieve Email Filtering:
Editheader Extension", RFC 5293, August 2008.
[RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322,
October 2008.
13.2. Informative References ๐
okay so these are the bonus reads, bestie ๐ they're not required to get the main spec working, but they're where the good background lives ๐ง โจ
- [RFC1991] Atkins, D., Stallings, W., and P. Zimmermann, "PGP Message Exchange Formats", RFC 1991, August 1996. ๐
- [RFC3851] Ramsdell, B., "Secure/Multipurpose Internet Mail Extensions (S/MIME) Version 3.1 Message Specification", RFC 3851, July 2004. ๐
- [RFC4871] Allman, E., Callas, J., Delany, M., Libbey, M., Fenton, J., and M. Thomas, "DomainKeys Identified Mail (DKIM) Signatures", RFC 4871, May 2007. ๐ฆ
- [RFC4880] Callas, J., Donnerhacke, L., Finney, H., Shaw, D., and R. Thayer, "OpenPGP Message Format", RFC 4880, November 2007. ๐ธ
Authors' Addresses ๐
Meet the people who wrote this whole thing, iykyk ๐
Tony Hansen
AT&T Laboratories
200 Laurel Ave.
Middletown, NJ 07748
USA
EMail: tony+sieveloop@maillennium.att.com
Cyrus Daboo
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
USA
EMail: cyrus@daboo.name
URI: http://www.apple.com/
That's a wrap on RFC 5703! ๐๐ Go be iconic with your new knowledge, bestie ๐ซถโจ
๐ฆ where this page comes from
- ietf: rfc5703 2009-10
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms