Proton 首頁

Sieve 篩選器 (進階自訂篩選器)

閱讀
11 分鐘
類別
接收與閱讀電子郵件

Proton Mail 為使用者提供了多種自動篩選電子郵件的方法,包括指派標籤或將其分類到資料夾中。一般而言,有以下三種方法:

  1. 將寄件者加入封鎖清單和允許清單,使其一律或永不被放入垃圾郵件資料夾中;
  2. 使用 Proton Mail 的互動式介面建立自訂篩選
  3. [最進階] 在 Sieve 中建立自訂篩選。

在這些方法中,在 Sieve 中建立自訂篩選提供了最大的靈活性,但使用起來也較為複雜。因此,我們認為 Sieve 是適合具備一定技術經驗使用者的進階功能。對於大多數使用者而言,互動式介面已足夠用來建立所需的自訂篩選。

目錄

什麼是 Sieve?

Sieve 是一種用於篩選電子郵件的程式語言。您可以透過編寫簡單的規則在 Sieve 中建立篩選器。例如:「將所有來自 Kyle 的訊息標上綠色標籤」。結合這些規則可以建立一個複雜的篩選系統。

您可以從頭編寫 Sieve 規則、參考本文章中的範例,或使用能讓此過程更簡單的軟體。

事實上,我們已經提供了一種使用互動式介面來建立 Sieve 篩選器的方法,該介面會使用您的輸入來產生 Sieve 篩選器。另一個學習 Sieve 的好方法是,使用互動式介面建立篩選器後,再在 Sieve 中編輯這些篩選器,因為互動式介面本身使用的是 Sieve 的子集。

例如,比較以下使用互動式介面建立的篩選器…


… 以及在 Sieve 編輯器中檢視相同篩選器的代碼:

本文章將向您介紹 Sieve 並說明如何撰寫您自己的 Sieve 篩選器。如果您需要關於使用 Sieve 的更多資訊,線上有很多其它教學課程可以提供協助。如果您有關於 Proton Mail 中的 Sieve 的問題,但在本頁面中找不到解答,您隨時可以聯絡支援團隊(按這裡)。

開始使用

若要開始建立 Sieve 篩選器,請登入 mail.proton.me(新視窗),然後前往 設定 → 所有設定 → Proton Mail → 篩選器 → 加入 Sieve 篩選器

Sieve 指令碼是由一連串的指令列表所組成。在大多數指令碼中,開頭都是 require 指令。require 指令會載入提供特定功能的延伸功能。例如,若要指派標籤或將訊息放入資料夾,我們需要 fileinto 指令。

若要載入此指令,我們只需輸入:

require "fileinto";

若要載入多個延伸功能,您可以使用列表:

require ["fileinto", "imap4flags"];

在此例中,imap4flags 會載入一個延伸功能,允許您將郵件標記為已讀。在 require 指令之後,您通常會對傳入的訊息執行一些測試。這是透過結合 if 與其它指令(例如 addressheader)來完成的。

最後,如果測試成功,您可以對訊息套用一項動作。例如,假設我們想將來自特定寄件者的所有電子郵件放入同一個資料夾,並將傳入的郵件標記為已讀。這可以寫成:

require ["fileinto", "imap4flags"];
# I don't really like Spott
if address :is "from" "Spott.Tenerman@northpark.example.com"
{ 
    addflag "\\Seen";
    fileinto "enemies";
}

請注意,# 符號表示評論,不會被解讀為 Sieve 指令碼的一部分。此外,您設定的資料夾或標籤(在此為 enemies)必須存在於您的環境中:您可以點擊這裡以了解如何建立資料夾和標籤。輸入此篩選器後,按「儲存」按鈕。您的篩選器現在將對每封傳入的電子郵件執行。

當然,您可能想將來自多個寄件者的電子郵件放入同一個資料夾。在這種情況下,您可以將字串列表傳遞給位址指令(字串(新視窗)是一連串的字元,在此例中為電子郵件地址):

require ["fileinto", "imap4flags"];
# I don't really like Spott and Kyyyhel
if address :is "from" ["Spott.Tenerman@northpark.example.com", "Kyhel.Broski@northpark.example.com"]
{ 
    addflag "\\Seen";
    fileinto "enemies";
}

請注意,每當您可以將字串傳遞給測試條件時,通常也可能傳遞一個列表。接著,它會嘗試透過比對列表中的任何字串來尋找相符項。這不適用於 fileinto、addflag 等指令。

但 Sieve 的功能不僅僅是重新排序您的電子郵件信箱。它還允許您拒絕電子郵件並附帶回應訊息:

require "reject";
# Reject mails that spell my name wrong
if header :contains "subject" "Kyhel"
{
    reject "My name is not Kyhel";
}

使用測試

在 Sieve 中結合測試

正如我們在 開始使用 區段中向您展示的您可以使用 if 指令對傳入的訊息執行測試,以決定電子郵件是否應受到 require 指令的影響。

除了 if 指令之外,還有其它的測試指令,可讓您以簡單的方式結構化您的指令碼。

Else

else 指令允許您在 if 指令未執行其操作時執行特定動作。範例如下:

require ["fileinto"];
# If the subject contains something incomprehensible, then put the mail into the kenny folder
if header :contains "subject" "mmph mmph"
{
    fileinto "Kenny";
} else { 
    fileinto "Understandable";
}

在此處,如果主旨完全是 mmph mmph,電子郵件將被移動到資料夾 Kenny。在其它情況下(即主旨不完全是 mmph mmph),電子郵件將被移動到資料夾 Understandable

Elsif

elsifelse if 的縮寫。與 else 指令相同,如果 if 條件不成立,則會執行它,但前提是 elsif 條件成立。如果 elsif 條件不成立,則會執行下一個 elsifelse 區塊。

require ["fileinto", "imap4flags"];
# If the subject contains something incomprehensible, then put the mail into the kenny folder
if header :contains "subject" "mmph mmph"
{
    fileinto "Kenny";
# Kyhel sends me only speeches
} elsif address :is "from" "Kyhel.Broski@northpark.example.com" { 
    fileinto "Speeches";
} else { 
# otherwise the mail is important, so add a star.
    addflag "\\Flagged";
}

請注意,在單次執行中,只有 ifelsifelse 區塊中的其中一個會被執行。

Anyof

有時,您需要在多個測試中有一個成功時執行指令。為此,您可以使用 anyof 指令。其寫法為先輸入 anyof,接著輸入左括號「(」,然後是以逗號分隔且您想要測試的陳述式,最後輸入右括號「)」。

require ["fileinto", "imap4flags"];
# Kenny either sends from kenny@northpark.example.com or puts "mmph mmph" in the subject.
   if anyof(address :is "from" "kenny@northpark.example.com", header :contains "subject" "mmph mmph")
{
    fileinto "Kenny";
}

此指令碼會將來自 kenny@northpark.example.com 或主旨中包含 mmph mmph 的訊息放入 Kenny 資料夾中。

Allof

anyof 對應的指令也存在:allof。這允許您僅在所有指定的條件都符合時執行指令:

require ["fileinto", "imap4flags"];
# Kenny always sends me mails with mmph mmph
if allof(address :is "from" "Kenny@northpark.example.com", header :contains "subject" "mmph mmph")
{
    fileinto "Kenny";
}


此指令碼會將來自 kenny@northpark.example.com 且主旨中包含 mmph mmph 的訊息放入 Kenny 資料夾中。

Not

最後,有時您需要在不符合某些條件時套用指令。在陳述式前加入 not 即可確保實現此目的:

require ["fileinto", "imap4flags"];
# If a subject line does not contain real guitar put it into the young people folder
if not header :contains "subject" "real guitar"
{
    fileinto "Young people";
}

這相當於:

require ["fileinto", "imap4flags"];
# The else part will be evaluated if the condition is not true
if header :contains "subject" "real guitar"
{
    # do nothing
} else {
    fileinto "Young people";
}

這會將主旨中不包含 real guitar 的所有電郵放入 Young people 資料夾中。

當然,您也可以將所有這些測試組合在一起。例如,如果您想在電郵既不是來自 Kenny 且主旨中不包含 mmph mmph 時,為該電郵加星號:

require ["fileinto", "imap4flags"];
if not anyof (    header :contains "subject" "mmph mmph", 
    address :is "from" "Kyhel.Broski@northpark.example.com" ) { 
    addflag "\\Flagged";
}

針對標頭執行測試

使用 address 指令,您可以對位址標頭(例如 fromtosender 標頭)執行測試。您可以使用以下標記之一來提取電郵位址的不同部分:

  • :localpart — @ 符號前的部分
  • :domain — @ 符號後的部分
  • :all — 整個位址

以下程式碼片段說明了此指令的使用方法:

require ["fileinto", "imap4flags"];
# Northpark people are made of paper, springfield are mostly yellow
if address :domain "from" "northpark.example.com"
{
    fileinto "PaperPeople";
} elsif address :domain "from" "springfield.example.com"{
    fileinto "YellowPeople";
}
if address :localpart "from" "chef"
{
    addflag "\\Flagged";
}

摘要來說,此指令碼會將從網域 northpark.example.com 寄出的所有郵件放入 PaperPeople ,並將從 springfield.example.com 寄出的郵件放入 YellowPeople

此外,不論電郵是從哪個網域寄出,如果 @ 前面的部分是 chef(例如 chef@example.com),則該訊息將被標記。另一個有趣的用法是自動將寄送到某個位址的所有郵件儲存在資料夾中:

require ["fileinto", "imap4flags"];
# Put support mail in a separate organized folder
if address :localpart "to" "support"
{
    fileinto "Support";
}

進階

envelope 指令允許您執行更多測試。一般而言,address 測試僅會從標頭中檢索值。然而,在 SMTP 工作階段中,您可以指定與標頭中不同的 from 位址。

在 Proton Mail 標頭介面中,envelope-from 等同於 return-path 標頭,而 envelope-to 則等同於 x-original-to 標頭。

使用 envelope 指令,您可以從信封(envelope)中檢索實際的 to:from: 位址。請注意,除了這兩個欄位之外,不存在其他欄位,因此 sender 在此指令中不存在。請注意,envelope 屬於延伸功能,因此需要您先 require(宣告需要)此延伸功能。

require ["fileinto", "imap4flags", "envelope"];
# Northpark people are made of paper, springfield are mostly purple
if envelope :domain "from" "northpark.example.com"
{
    fileinto "PaperPeople";
} elsif envelope :domain "from" "springfield.example.com"{
    fileinto "PurplePeople";
}
if envelope :localpart "from" "chef"
{
    addflag "\\Flagged";
}

使用比較器來評估兩個值

當測試評估兩個值時,可以使用稱為比較器(comparators)的不同標記來指定此比較的進行方式。在此之前,我們已經使用了兩個比較器::is:contains,它們分別檢查指定的字串是否與特定值完全相同,以及該特定值是否包含指定的字串,如以下測試所示。

require ["fileinto", "imap4flags"];
if not anyof (
    header :contains "subject" "mmph mmph", # the subject contains mmph mmph 
    address :is "from" "Kyhel.Broski@northpark.example.com" # the recipient is exactly Kyhel.Broski@northpark.example.com
) { 
    addflag "\\Flagged";
}

比較器 :matches 也可以用來定義更具體的格式。它會從頭到尾比較兩個值,就像比較器 :is 一樣。然而,在使用 :matches 的情況下,您定義的值可以包含 ?* 等值。問號將符合單個字元,而星號(稱為萬用字元)將符合零或多個字元。

透過此格式,您可以建立此測試:

require ["fileinto", "imap4flags"];
if header :matches "subject" "mmph*" { 
    addflag "\\Flagged";
}

在此範例中,如果訊息的主旨以 mmph 開頭,且其後包含任何一個或多個字元,則測試將成功。換句話說,當主旨以「mmph」開頭時,該電郵將被加上標記。「mmph mmph」和「mmph mmph Hello」皆符合條件;「Hello mmph」和「Springfield sales」則不符合。

星號也可以用在值的內部且可使用多次,如下所示:

require ["fileinto", "imap4flags"];
if header :matches "subject" "mmph *mmph *mmph" { 
    addflag "\\Flagged";
}

如果主旨以「mmph 」(含空格)開頭,並包含另一個「mmph 」(含空格),最後以「mmph」(不含空格)結束,則此測試符合條件。符合的主旨包括「mmph mmph mmph」、「mmph mmph mmphmmph」或「mmph is mmph and mmph」。

:matches 比較器在進行位址比較時非常實用。您可能知道,Proton Mail 有多個網域:protonmail.comproton.me。如果您想要檢查訊息是否來自 Proton Mail 使用者,您可以使用此指令碼:

require ["fileinto", "imap4flags"];
# Put support mail in a separate organized folder
if address :domain :matches "from" "protonmail.*"
{
    fileinto "Internal";
}

如果出於某種原因您需要精確符合字元 *?,則可以透過在前面加入 \\引用(quote)它們:\\* 將符合星號,而 \\? 將符合問號。

請注意,我們也支援 regex 延伸功能,這也定義了比較器 :regex。此比較器是 :matches 的更精確版本,但非常複雜。如需更多資訊,請閱讀官方文件(新視窗)

在某些情況下(如您將在本文後續內容中所見),您可能想要比較數值。relational 套件就是為此用途而設計。此套件定義了比較器 :value,其後會加上比較類型。

它允許您檢查某個值是否大於(比較類型為 “gt”)、大於或等於(”ge”)、等於(”eq”)、小於或等於(”le”)或小於(”lt”)指定的值。

在比較數值時,comparator-i;ascii-numeric 套件也非常實用。它會告訴指令碼直譯器,該字串的內容是數字,而不是 一般字串。可以透過在測試中加入 :comparator “i;ascii-numeric” 來使用它。

有了所有這些資訊,我們就可以建置以下指令碼:

require ["fileinto", "relational", "comparator-i;ascii-numeric"];  
if header :value "ge" :comparator "i;ascii-numeric" "subject" "2"   
{    
 fileinto "Dummy example";
}

如果主旨大於或等於 2,此測試會將訊息移動至 Dummy example 資料夾。如果主旨不是數字而是文字,則測試將失敗。因此,這個範例看起來非常愚蠢,但它旨在與其他延伸功能(如我們稍後將在本文中定義的 date)結合使用。

在 Sieve 中使用上下文進行比較

您也可以使用延伸功能來存取與您的帳號及一般 Proton Mail 上下文相關的資訊。例如,您可以檢查寄件者位址是否在您的通訊錄列表中。

存取您的通訊錄列表

您可以使用 extlists 延伸功能來存取您的通訊錄列表。結合標頭測試,您便可以檢查聯絡人是否在您的通訊錄列表中。

require ["fileinto", "extlists"];  
# Checks that the sender is in your personal address book
if header :list "from" ":addrbook:personal?label=Family"   
{    
 fileinto "Known"; 
}

如果寄件者包含在列表 :addrbook:personal?label=Family 中,此測試將為訊息標記上 Known 標籤。該列表可分為兩部分。首先,:addrbook:personal 表示該位址在您的個人通訊錄中。其次,label=Family 進一步縮小列表範圍,指定聯絡人除了在您的通訊錄中之外,還必須屬於 Family 通訊群組。如有需要,您可以將此標籤變更為另一個通訊群組。如果您願意,可以使用 :addrbook:personal?label=Work,在這種情況下,僅當寄件者在您的通訊錄中且屬於 Work 通訊群組時,測試才會成功。

更一般地說,列表遵循 Tag URI Scheme(新視窗),您可以加入額外的參數來縮小篩選器的範圍。然後,您可以按照以下方式使用此列表:

require ["fileinto", "extlists"];  
# replace :your:list:here by the list you want to use
if header :list "from" ":your:list:here"
{    
 # some actions... 
}

我們提供了四個不同的列表:

  • :addrbook:personal¹ 檢查位址是否在您的通訊錄列表中。該列表接受 label 參數,其與特定的通訊群組相符合。此參數可分為四種子版本:
    • :addrbook:personal?label=something 將符合 “something” 通訊群組中的聯絡人;
    • :addrbook:personal?label.starts-with=something 將符合屬於至少一個以 “something” 開頭的群組的聯絡人;
    • :addrbook:personal?label.ends-with=something 將符合屬於至少一個以 “something” 結束的群組的聯絡人;
    • :addrbook:personal?label.contains=something 將符合屬於至少一個包含 “something” 的群組的聯絡人。

您也可以存取與相符電郵相關的加密資訊:

  • :addrbook:personal?keypinning=true 將符合擁有信任金鑰的聯絡人。將 true 改為 false 則會符合不擁有信任金鑰的聯絡人;
  • :addrbook:personal?encryption=true 將符合已啟用加密的聯絡人。將 true 改為 false 則會符合未設定或已停用加密的聯絡人;
  • :addrbook:personal?signing=true 將比對已啟用簽署的聯絡人。將 true 改為 false 則會比對已停用簽署的聯絡人。
  • :addrbook:myself¹ 比對所有屬於您自己的位址;
  • :addrbook:organization 比對所有屬於您成員所在組織中某人擁有的位址;
  • :incomingdefaults:inbox 檢查該位址是否在您的允許清單中;
  • :incomingdefaults:spam 檢查該位址是否在您的封鎖清單中。

結合變數延伸功能(在下一個段落中說明),比對變數將會被改變。比對變數 ${0} 將一律包含指定列表中所含的最後一個電郵位址。如果該列表有標記備註 1,比對變數 ${1} 則會包含顯示名稱。

例如,使用以下列表,您可以建立一個篩選器,用來刪除從您的家庭或白名單以外的任何人所接收的所有電郵:

require "extlists";  
# checks that the sender is not in the contact group Family, whilelisted or yourself
if not anyof(
    header :list "from" ":addrbook:personal?label=Family", 
    header :list "from" ":incomingdefaults:inbox",
    header :list "from" ":addrbook:myself"
) {    
  discard; # permanently delete the email
}

如果符合該條件,則會執行 discard(捨棄)動作。此動作會立即且永久刪除該電郵。您也可以簡單地使用 fileinto 動作,將其移動到垃圾桶資料夾以代替捨棄:fileinto “trash”;.

建立變數

管理內容時另一個實用的工具是 variable(變數)定義。變數是一個暫時的儲存空間位置,您可以在其中放入文字並用名稱標記它。稍後,您將能夠透過呼叫其名稱來重複使用此內容。例如,您可以使用以下指令碼:

require ["reject", "variables"];
# First check who is the sender
if allof(
    address :is "from" "Kenny@northpark.example.com", 
    header :contains "subject" "mmph mmph"
) {
    # It's from Kenny!
    # Create the variable message containing 'mmph mmph'
    set "message" "mmph mmph";
} else {
    # Create the variable message containing 'Sorry, I don't want emails today!'
    set "message" "Sorry, I don't want emails today!";
}
# Then, reject the message
reject "${message}";

此指令碼的目的在於使用自訂的訊息來拒絕電郵。如果原始電郵來自 kenny 且其主旨為「mmph mmph」,則會建立包含 mmph mmph 的變數「message」。在其它情況下,訊息將會填入「Sorry, I don’t want emails today!」。接著,在最後一個步驟中,我們在拒絕指令中重複使用此變數。

Sieve 本身並不支援定義變數,因此變數是在 variables 延伸功能中定義的,必須在您指令碼的開頭處要求載入。有兩種方法可以定義變數。

  • 明確建立變數:

提供了 set 動作來建立變數。

require "variables";
# Create a variable called "labelname" and containing the string "Work".
set "labelname" "Work";

第一個字串是您變數的名稱,第二個則是您變數的值。因此先前的範例建立了一個名為 labelname 且包含 Work 的變數。

一旦定義了變數,您就可以在字串中加入以下格式來呼叫它:${name},其中 name 是您變數的名稱。執行時,它將會被變數的值取代。(如果您尚未定義該變數,它將會被空字串取代。)因此,在以下指令碼中:

require "variables";
require "fileinto";
# Create a variable called "labelname" and containing the string "Work".
set "labelname" "Work";
# Move the email in "${foldername}/${labelname}" which becomes after variable resolution "/Work";
fileinto "${foldername}/${labelname}";

您的電郵將會被貼上 /Work 標籤。因為我們已經定義了變數 labelname,因此它會被替換為 Work。然而,foldername 未被定義,因此它會直接被移除。

  • 隱式指派變數:

變數最有趣的使用案例是在使用 :matches 測試時。讓我們看以下範例,其中電郵寄件者為 test@proton.me

require "variables";
require "fileinto";
# do a matches test 
if header :matches "from" "*@*" {
    # The first * matches "test", the second "protonmail".  
    # Thus, the first matching variable contains "test"
    fileinto "${1}";
}

與變數延伸功能搭配使用時,match 操作的結果將會儲存在變數中。多個變數將會設定為數值名稱。首先,變數 0 將包含完整的比對結果(在我們的範例中將是完整的位址:test@proton.me)。接著,第一個比對群組將會指派給變數 1(在我們的範例中為 test),第二個比對群組將會指派給第二個變數(proton.me),依此類推,直到最後一個比對群組。

在我們的範例中,會執行 fileinto 指令。位置被定義為 ${1},這會被辨識為變數,因而被上述計算出的值取代:test

請注意,也可以在使用正規表示式比對群組的 :regex 測試中指派變數。

轉換變數

一個不錯的可能性是轉換變數。為此,可以將 set 關鍵字與旗標組合搭配使用,以便在將值指派給變數之前先變更該值。

  • :lower 將會把變數值變更為小寫;
  • :upper 將會把變數值變更為大寫;
  • :lowerfirst 將會把變數值的第一個字母變更為小寫;
  • :upperfirst 將會把變數值的第一個字母變更為大寫;
  • :quotewildcard 將會引用字串中所包含的任何萬用字元,以便可以在比對陳述式中按字面意思使用;
  • :length 將會傳回該值的長度。

請注意,您也可以在另一個 set 動作中重複使用已定義的變數。讓我們改進我們先前的範例:

require "variables";
require "fileinto";
# Set labelname to WORK, and modify it to lowercase with the first letter in upper case 
set :lower :upperfirst "labelname" "WORK";
set :lower :upperfirst "foldername" "geneva";
# Create a variable that is a combination of foldername and labelname
set "location" "${foldername}/${labelname}";
fileinto "${location}";

篩選器將會逐步建立三個變數。第一個指令 set 將會建立變數 labelname。該變數的內容為 Work。事實上,原始值 WORK 是同時使用 :lower:upperfirst 旗標進行轉換,將大小寫先變更為 work,接著再變更為 Work

第二個 set 指令將會建立第二個名為 foldername 且包含字串 Geneva 的變數。事實上,這裡使用了 :lower:upperfirst 旗標。

最後,會建立變數 location。值 “${foldername}/${labelname}” 包含兩個變數:foldernamelabelname。因此 Sieve 解譯器會將這些變數替換為其值:Work 和 Geneva。

最後,變數 location 會作為 fileinto 指令的引數。因此,電郵將會被移動到其名稱為變數 location 之值的資料夾:Work/Geneva

比較器也可以套用到比對變數:

require "variables";
require "fileinto";
if address :all :matches "from" "*@*" {
    set :lower :upperfirst "fileintovar" "${1}";
    fileinto "${fileintovar}";
}

在這裡,如果電郵的寄件者是 test@proton.me,它將會被加上 Test 標籤。

變更變數值的另一種方法是使用 vnd.proton.eval 延伸功能。此延伸功能定義了新的旗標 :eval,這將允許您進行一些簡單的計算:

require "variables";
require "fileinto";
require "vnd.proton.eval";
# do a match test on the sender address
if header :matches "from" "*" {
    # create a variable called length, containing the length of the first     
    # matching variable
    set :length "length" "${1}"; 
    # Create a variable called fileintovar containing the result of the expression written below
    set :eval "fileintovar" "${length} * 25 - 1 / 8+3";
    fileinto "${fileintovar}";
}

在此範例中,且仍考慮電郵是來自 test@proton.me,該電郵將會被標記上值 478。事實上,第一個比對變數的長度是 19,而 19 * 25 – 1 / 8 + 3 的結果會無條件進位到 478

這在起初可能顯得無用,但此延伸功能在與其它操作結合時會更有意義。

與 Sieve 中其它欄位的比較

比對特定標頭也是可行的。例如,若要將所有傳送到列表的訊息(通常是行銷訊息或電子報)放置在一起,您可以這樣做:

require "fileinto";
# Filter all lists into the same folder
if exists "list-unsubscribe"
{
    fileinto "advertisements";
}

若要將社群媒體電郵分類到其專屬的資料夾中,您可以編寫:

require "fileinto";
# Filter all lists into the same folder
if anyof(exists "x-facebook", exists "x-linkedin-id") {
    fileinto "social";
} elsif exists "list-unsubscribe"
{
    fileinto "advertisements";
}

請注意,我們使用的是:

anyof(exists "x-facebook", exists "x-linkedin-id")

而不是:

exists ["x-facebook", "x-linkedin-id"]

因為後者會檢查 x-facebookx-linkedin-id 是否皆已設定。

若要實際查看標頭包含什麼值,您可以使用 header 測試:

require "fileinto";
# Put all mails that have been sent without TLS/SSL into the same folder
if header :is "x-pm-transfer-encryption" "none" {
    fileinto "unencrypted";
}

除了進行精確比對的 :is 操作之外,header 指令也支援 :matches(使用萬用字元進行比對,例如 “*@*.com” 將比對任何以 .com 結束的電郵位址),以及用來檢查標頭是否包含特定字串的 :contains 指令。

若要設計 Sieve 篩選器,擷取電郵的標頭會很有用。要在 Proton Mail 網頁介面中執行此操作,請前往更多 () → 檢視標頭。系統將會打開一個包含該電郵所有標頭的新視窗。

在 Sieve 中使用訊息大小進行篩選

您可以對大型電子郵件與小型電子郵件進行不同的處理。例如,您可能希望為大型電子郵件加上標記,以便刪除它們以節省電子郵件信箱空間。這可以透過以下方式完成:

require ["imap4flags"];
# Flag emails that probably have large attachments (> 2 MiB)
if size :over 2M # you can also use 2097152 if you want, they are synonymous
{
    addflag "\\Flagged";
}
# Automatically mark as read really small messages. They can't have much content anyway...
if size :under 1000
{
    addflag "\\Seen";
}

如您所見,如果您想指定較大的大小,可以使用單位,只需在數字後方加入對應預期單位的字母即可。共有三個可用單位:K 代表 kibioctet(或 1024 位元組)、M 代表 mebioctet(或 1 048 576 位元組)以及 G 代表 gibioctet (或 1 073 741 824 位元組)。

請注意,在此情況下「over」表示大於,「under」表示小於。這意味著如果訊息的大小剛好是 1000 位元組,則兩者皆不

size :under 1000

也不

size :over 1000

會符合。

請注意,Sieve 篩選器無法存取實際內容,僅會顯示已加密的大小。

對訊息執行進階操作

您可以在 Sieve 中對訊息執行不同的回應。我們已在先前的章節中介紹了 fileintoaddflagdiscardreject 等操作。在這裡,我們將介紹更多進階操作。

假期訊息與日期測試

您可以在 Sieve 中複製 自動回覆 功能,只需使用 vacation 指令即可。事實上,您「設定」中的自動回覆功能就是依賴 Sieve 來運作。但是透過在指令碼中使用假期選項,您將擁有更多自訂自動回覆的可能性。例如,您可以根據條件自訂特定的訊息。備註:與「設定」中的自動回覆功能一樣,vacation 動作僅適用於付費方案。

vacation 指令會向嘗試與您聯絡的任何人傳送假期回覆。它通常與 currentdatedate 測試結合使用,以便在特定時間範圍內傳送回覆。

假設我將於科羅拉多時間 2017 年 7 月 14 日至 2017 年 8 月 14 日期間度假。我可以使用以下 Sieve 代碼來設定自動回覆:

require ["date", "vacation", "relational"];
if allof(currentdate :zone "US/Mountain" :value "ge" "date" "2017-07-14",
 currentdate :zone "US/Mountain" :value "le" "date" "2017-08-14")
{
    vacation "Queue you guys, I'm going on vacation.";
}

vacation 指令的其中一些選用引數為 :handle:days。預設情況下,Sieve 不會在稱為逾時(timeout)的特定天數內,向同一個寄件者多次回覆。這可以防止您無意中傳送大量的自動電子郵件。

若要控制逾時,您可以使用參數 :days:days 引數用於指定保留位址且不予回應的期間,並且一律以天數指定。有時,您的 Sieve 指令碼中有多個 vacation 指令,並且您需要確保其中每一個指令都至少傳送一次回覆(如果規則符合)。在這種情況下,可以使用 :handle 選項。:handle 的引數是識別所傳送回覆類型的字串。

為了了解這是如何運作的,假設您是一位老師。老師經常透過電子郵件收到家庭作業。將它們分類到各自的資料夾中非常有用。此外,您可以拒絕在截止日期之後提交的任何作業。

在這種情況下,您可能希望使用 handle 來確保在需要時傳送回覆:

require ["date", "vacation", "reject", "fileinto", "relational"];
if header :contains "subject" "Homework assignment 1"
{
    # remind people not to forget the attachments
    if size :under 5000
    {
        vacation :handle "Homework assignment 1 - missing attachment" "Your message size is really low. Please make sure you didn't forget to add the homework as an attachment.";
    }
   
    # check if the student made the deadline
    if  currentdate :zone "US/Mountain" :value "le" "date" "2017-06-12"
    {
        fileinto "Homework Assignment 1";
    } else {
        reject "Too late, you missed the deadline.";
    }
}
if header :contains "subject" "Homework assignment 2"
{
    # remind people not to forget the attachments
    if size :under 5000
    {
        vacation :handle "Homework assignment 2 - missing attachment" "Your message size is really low. Please make sure you didn't forget to add the homework as an attachment.";
    }
   
    # check if the student made the deadline
    if  currentdate :zone "US/Mountain" :value "le" "date" "2017-06-12"
    {
        fileinto "Homework Assignment 2";
    } else {
        reject "Too late, you missed the deadline.";
    }
}

以下是假期回覆允許的所有引數,依應傳遞的引數順序列出:

  • :days 是自動回覆程式在傳送假期訊息後,應避免向同一個寄件者傳送回覆的天數
  • :subject 是自動回覆程式回覆寄件者時應使用的前綴(預設為 auto)。例如,「Homework Assignment 2」將會收到帶有「late: Homework Assignment 2」的回覆,如果傳遞了 :subject “late” 的話。
  • :mime 表示回覆的第一行使用的是特定格式。這允許寄件者以 html 訊息進行回應。例如,要編寫 html 回應,請傳遞 :mime 引數,並在回應的第一行中寫入 Content-Type : text/html
  • :handle 是用來識別所傳送回覆類型的字串。

請注意,:zone 參數(在 currentdate 中)是選用參數,如果未設定,將使用伺服器的本地時間(如果是 Proton Mail,則為瑞士日內瓦)。

區域(zone)參數接受時區偏移量,即格式為「+0100」(代表 UTC+1)的字串,以及 ICANN 資料庫中的實際時區(請參閱 https://en.wikipedia.org/wiki/List_of_tz_database_time_zones(新視窗))。最後一個選項通常更有用(雖然是非標準的 Sieve),因為它也編碼了每個時區的日光節約時間。

您可以使用標準的 :is/ :contains/ :matches 參數來比較日期。例如,以下 Sieve 指令會符合 2017 年 7 月中的任何日期:

currentdate :zone "US/Mountain" :matches "date" "2017-07-??"

但在大多數情況下,:value 參數要有用得多。

您需要傳遞的最後一個參數是格式。該格式也編碼了您想要比較日期的哪一部分。在給定的範例中,我們使用了日期格式。所有支援的格式為:

  • year,以「0000」到「9999」格式編碼的年份
  • month,以「01」到「12」編碼的月份
  • day,以「01」到「31」編碼的日期
  • date,編碼為 yyyy-mm-dd
  • hour,以「00」到「23」編碼的小時
  • minute,以「00」到「59」編碼的分鐘
  • second,以「00」到「60」編碼的秒(60 是閏秒(新視窗),僅在科學家認為有需要時才會在 23:59:60 出現)
  • time,格式為 hh:mm:ss 的時間
  • iso8601,符合 ISO8601 標準的日期和時間,例如:2005-08-15T15:52:01+00:00
  • std11,符合 RFC2822 標準的日期和時間,例如:Mon, 15 Aug 2005 15:52:01 +0000
  • zone,格式為 +/-zzzz 的時區偏移量,例如 +0000 或 -1200
  • julian,自世界協調時間(UTC)1858 年 11 月 17 日起的天數
  • weekday,一星期中的日子,從星期日為 0 開始到星期六為 6

最後,也可以從標頭中檢索日期,而不是使用 currentdate。這個日期指令的運作方式與 currentdate 相同,不同之處在於它在格式字串之前需要一個額外的字串:標頭名稱。例如:

date :zone "US/Mountain" :matches "received" "date" "2017-07-??"

請注意,標頭不一定是準確的:寄件者可以隨意更改它們,因此不可靠。

注意事項:

  1. 自動回覆程式不會對自動產生的訊息做出回應,例如郵寄清單、由其他自動回覆程式傳送的電子郵件,或由 noreply 位址傳送的訊息。
  2. 自動回覆程式不會向同一個電子郵件地址多次傳送訊息,除非 vacation 指令具有不同的 :handle。

管理過期

Proton Mail 的一項獨特功能是能夠對寄出的訊息設定過期時間,屆時該訊息將自收件者的電子郵件信箱中刪除。

您也可以透過加入過期時間,使用此功能來管理您的收件訊息:

require "vnd.proton.expire"; 
# permanently delete all incoming and outgoing emails after 10 days
expire "day" "10";

上述指令碼將在 10 天後刪除任何收到的電子郵件。這有點極端,因為它適用於所有電子郵件。相反地,您應該使用條件來將指令碼僅套用到特定的一組電子郵件。例如,您可以讓來自不在您通訊錄中的聯絡人的任何訊息過期:

require ["extlists", "vnd.proton.expire"];
# permanently delete after 10 days any email not from me or from someone in my address book.
if not anyof(
    header :list "from" ":addrbook:personal",
    header :list "from" ":addrbook:myself"
) {
 expire "day" "10";
}

備註:如果指定的過期時間超過 730 天,它將自動限制在 730 天。

Sieve 的限制

有幾點 Sieve 限制您需要注意。

  • 已傳送的訊息無法手動或透過篩選器移動至「收件匣」或「草稿」。它們會一直保留在「寄件備份」資料夾,以及使用者或篩選器套用的資料夾/標籤中。
  • 收到的訊息無法手動或透過篩選器移動至「草稿」或「寄件備份」。
  • 「草稿」無法手動或透過篩選器移動至「收件匣」或「寄件備份」。
  • 對於「垃圾郵件」中的訊息(或是在處理過程中歸類為垃圾郵件的訊息),我們不會傳送自動回覆/假期回覆訊息。如果您需要此功能,請考慮加入自訂資料夾(例如 mySpam)並停用其通知。
  • 自動回覆/假期回覆訊息的限制

關於正規表示式支援的備註

Proton 的 Sieve 實作遵循 Sieve 電子郵件篩選標準,其僅包含最低限度的正規表示式支援。部分常見的正規表示式速記語法,例如 \b(單字邊界)、\w(單字字元)、\W(非單字字元)及 \d(數字),在 Sieve 中皆不受支援。因此,在篩選器中使用這些速記字元可能會導致其無預警失效。此限制源於 Sieve 標準本身,該標準優先考慮跨平台的簡易性與相容性。如需完整詳細資訊,請參閱 Sieve 正規表示式草稿 RFC。

支援的操作和測試列表

套件

Sieve 支援以下延伸功能。您可以參考官方文件以取得更多資訊。

日期

  • 用法: date
  • 描述: (新視窗)提供檢查日期資訊的方法。
  • 說明文件: https://tools.ietf.org/html/rfc5260(新視窗)
  • 實作: 預設比較器為 i;ascii-numeric 而非 i;ascii-casemap。事實上,日期搭配 casemap 比較器並無作用。
  • 請參閱: 假期回覆訊息與日期測試

Envelope

FileInto

  • 用法: fileinto
  • 描述: 將標籤套用至訊息,或將其移動至資料夾。
  • 說明文件: https://tools.ietf.org/html/rfc5228#section-4.1(新視窗)
  • 實作: 斜線表示資料夾的完整路徑,若標籤名稱包含斜線,則必須進行跳脫。支援以下選項:
    • Work“: 這是名為「Work」的標籤或資料夾
    • Work/Project1“: 這是位於「Work」資料夾中的「Project1」子資料夾
    • Work/Project1/Docs“: 這是位於「Work」資料夾內「Project1」子資料夾中的「Docs」子資料夾
    • Work/Misc\\/Others“: 這是位於「Work」資料夾中的「Misc/Others」子資料夾
  • 請參閱: 開始使用

Imap4flags

Reject

Vacation

Variables

Relational

  • 用法:relational
  • 描述:提供關聯比對運算子。
  • 文件:https://tools.ietf.org/html/rfc5231

Regex

  • 用法:regex
  • 描述:提供 regex 比對運算子。
  • 文件:https://tools.ietf.org/id/draft-ietf-sieve-regex-01.html

Ascii 數值比較器

外部儲存的列表

  • 用法:extlists
  • 描述:提供通訊錄列表的存取。
  • 文件:https://tools.ietf.org/html/rfc6134(新視窗)
  • 實作:支援以下列表
    • addrbook:personal:個人通訊錄列表。支援以下查詢:
      • label[.starts-with / .ends-with / .contains]=<group: string>:針對通訊群組的操作;
      • keypinning=<value: true / false> 聯絡人的公開金鑰定義;
      • encryption=<value: true / false> 聯絡人的預設加密;
      • signing=<value: true / false>  聯絡人的預設簽名。
    • :addrbook:myself 屬於目前使用者的位址;
    • :addrbook:organization 屬於目前組織成員的位址;
    • :incomingdefaults:inbox 允許清單
    • :incomingdefaults:spam 封鎖清單
  • 請參閱:存取您的通訊錄列表

Eval

  • 用法:vnd.proton.eval
  • 描述:評估字串中給出的簡單算術函數。
  • 文件:轉換變數

Include

過期

  • 用法:vnd.proton.expire
  • 描述:管理訊息過期。
  • 文件:管理過期

測試

Currentdate

  • 用法:
currentdate [":zone" <time-zone: string>] [COMPARATOR] [MATCH-TYPE] <date-part: string> <key-list: string-list>

日期

  • 用法:
date [":zone" <time-zone: string> / ":originalzone"] [MATCH-TYPE] <header-name: string> <date-part: string> <key-list: string-list

HasFlag

  • 用法:
hasflag [MATCH-TYPE] [COMPARATOR] <list-of-flags: string-list>
  • 描述:測試特定訊息是否具有特定標記。
  • 套件:imap4flags
  • 請參閱:開始使用

Envelope

  • 用法:
envelope [COMPARATOR] [ADDRESS-PART] [MATCH-TYPE] <envelope-part: string-list> <key-list: string-list>

位址·

  • 用法:
address [COMPARATOR] [ADDRESS-PART] [MATCH-TYPE] <header-list: string-list> <key-list: string-list>

標頭

  • 用法:
header [COMPARATOR] [MATCH-TYPE] <header-names: string-list> <key-list: string-list>

HasExpiration

  • 用法
hasexpiration
  • 描述:測試訊息是否已設定過期時間。
  • 套件:vnd.proton.expire

Exists

  • 用法:
exists <header-names: string-list>

過期

  • 用法:
expiration :comparator "i;ascii-numeric" [MATCH-TYPE] <unit: "day" / "minute" / "second"> <key-list: string-list>
  • 描述:將訊息過期時間與給定的鍵值進行比較。如果對不會過期的訊息執行此測試,測試將會失敗。
  • 套件:vnd.proton.expire

Size

  • 用法:
size <":over" / ":under"> <limit: number>

String

  • 用法:
string [MATCH-TYPE] [COMPARATOR] <source: string-list> <key-list: string-list>
  • 描述:評估任一來源字串是否與任一鍵值相符。
  • 套件:variables

Anyof

  • 用法:
anyof <tests: test-list>
  • 描述:對提供給它的測試進行邏輯 OR 運算。
  • 套件:<預設>
  • 請參閱: 開始使用

Allof

  • 用法:
allof <tests: test-list>
  • 描述:對提供給它的測試進行邏輯 AND 運算。
  • 套件:<預設>
  • 請參閱:開始使用

Not

  • 用法:
not <test: test>
  • 描述:反轉給定測試的結果。
  • 套件:<預設>
  • 請參閱:開始使用

True

  • 用法:
true
  • 描述:一律相符。
  • 套件:<預設>

False

  • 用法:
false
  • 描述:永不相符。
  • 套件:<預設>

操作

Require

  • 用法:
require <packages: string-list>
  • 描述:載入指定的延伸功能,以便能使用其方法或修改。
  • 套件:<預設>
  • 請參閱: 開始使用

FileInto

  • 用法:
fileinto <folder: string>
  • 描述:將正在處理的訊息移動至特定的資料夾。
  • 套件:fileinto
  • 請參閱:開始使用

Addflag

  • 用法:
addflag <list-of-flags: string-list>
  • 描述:將指定的標記加入至正在處理的訊息。
  • 套件:imap4flags
  • 請參閱:開始使用

Removeflag

  • 用法:
removeflag <list-of-flags: string-list>
  • 描述:自正在處理的訊息中移除指定的標記。
  • 套件:imap4flags

Setflag

  • 用法:
setflag <list-of-flags: string-list>
  • 描述:移除全部標記,並在正處理的訊息上設定指定的標記。
  • 套件:imap4flags

Stop

  • 用法:
stop
  • 描述:停止處理全部 Sieve 篩選器。後續的 Sieve 篩選器將不會執行。
  • 套件:<預設>

Return

  • 用法
return
  • 描述停止處理目前的 Sieve 篩選器。後續的 Sieve 篩選器仍會執行。
  • 套件include

Set

  • 用法:
set [MODIFIER] <name: string> <value: string>
  • 描述:建立將指定名稱與指定值關聯的新變數。
  • 套件: variables
  • 請參閱:建立變數

Discard

  • 用法:
discard
  • 描述:在此 Sieve 篩選器結束時捨棄訊息。捨棄後,將不會執行其它 Sieve 篩選器。
  • 套件:<預設>

Keep

  • 用法:
keep
  • 描述:還原上一個捨棄指令。只有在同一個 Sieve 篩選器中時才會生效。如果尚未執行任何捨棄操作,則此指令將不執行任何動作。
  • 套件:<預設>

Reject

  • 用法:
reject <reason: string>
  • 描述:傳送電子郵件至寄件者的 SMTP 位址並附上原因,且立即捨棄此訊息。keep 指令將不會取消此動作。
  • 套件:<預設>
  • 請參閱:開始使用假期訊息與日期測試

Expire

  • 用法:
expire <unit: "day" / "minute" / "second"> <value: string>
  • 描述:在指定的時間後使訊息過期。
  • 套件:vnd.proton.expire
  • 請參閱:管理過期

Unexpire

  • 用法:
unexpire
  • 描述:移除訊息的過期時間。
  • 套件:vnd.proton.expire

Vacation

  • 用法:
vacation [":days" number] [":subject" string] [":mime"] [":handle" string] <reason: string>
  • 描述:傳送自動回覆至寄件者的 SMTP 位址,並以指定的原因作為內文。
  • 套件:vacation (需要付費帳號)
  • 請參閱:假期訊息與日期測試

Valid External List

  • 用法:
valid_ext_list <ext-list-names: string-list>
  • 描述:測試全部指定的外部列表是否均受支援且有效。
  • 套件:extlists