目錄
介紹
電郵位址格式
1. Address
2. addr-spec
有效的電子郵件位址
顯示名稱
注釋
引号
一些看起來很奇怪的有效位址
Domain-Part要求
不使用ASCII字元(UTF8)
長度限制
非法的電子郵件位址
推薦建議
使用代碼
配置EmailTextBox
執行個體屬性
靜态特性
擷取代碼
驗證電子郵件位址很困難,因為構成有效電子郵件位址的規範允許使用大量電子郵件。試圖将這些規範轉換為适當的Regex會導緻龐大而複雜的表達式,但仍可能無法涵蓋所有情況。本文介紹如何合理地完成電子郵件位址驗證,并提供生産品質代碼WPF文本框,包括讓使用者僅輸入有效的擊鍵(keystrokes),控制是否必須輸入電子郵件位址(必填字段),,以及在使用者試圖關閉視窗而不儲存所做的更改時發出警報。
介紹
編寫用于驗證電子郵件位址的WPF控件是一個挑戰,因為幾乎允許所有Unicode字元和許多格式。規範允許使用多種格式,但實際上隻使用了很少的格式,因為異國情調的格式可能會被某些電子郵件軟體(Outlook等用戶端,Exchange等伺服器)拒絕。控件必須足夠靈活才能滿足您的要求,即,如果您需要使用精确格式的嚴格控件,或者隻想在使用者鍵入奇怪的電子郵件位址時提醒使用者。當然,最好的辦法是防止使用者進行無效的輸入并控制使用者可以進行的擊鍵(keystrokes)。由于此控件是WpfWindowLib的一部分,是以如果需要或缺少電子郵件位址,它不允許使用者儲存資料。它還會通知使用者是否試圖關閉視窗而不儲存資料。
電郵位址格式
相關規範可以在RFC 5322:Internet消息格式:位址規範中找到。
它通過兩個步驟定義了一個有效的電子郵件位址:
1. Address
這個更高的級别指定了一個Address 可以包含一個display-name和一個Addr-Spec,這是我們在談論電子郵件位址時通常指的部分。Address 看起來是這樣的:
John Doe<[email protected]>
- 顯示名稱為“John Doe”。它不用于電子郵件的路由,但允許以更加使用者友好的形式顯示電子郵件位址。
- “<[email protected]>”:在規範angle-addr中被調用,并在尖括号中包含addr-spec(用于路由電子郵件的電子郵件位址)。
顯示名稱是可選的。如果沒有顯示名稱,則不需要尖括号。
2. addr-spec
這部分描述通常稱為電子郵件位址的内容:
[email protected]
基本上,位址分為兩部分:
local-part @ domain-part
domain-part是電子郵件伺服器的網際網路DNS位址,同時local-part是該電子郵件伺服器中的“信箱”的名稱。domain-part的定義非常明确,每個人都需要了解電子郵件位址的路由,而本地部分的确切含義是由接收電子郵件伺服器軟體定義的,發件人不一定需要了解本地部分結構。該規範希望給電子郵件伺服器盡可能的自由,這使得很難驗證電子郵件位址是否正确。
有效電子郵件位址的唯一公認的要求是:
必須有兩個部分,正好用'@'分隔。
但是,即使這個簡單的規範也不總是正确的,因為以下也是有效的電子郵件位址:
"[email protected]"@example.com
第一個'@'在帶引号的字元串中。所有可見的ASCII字元(即,從0x21到0x7E)被允許在local-part中使用,當它們被引用時。它們可以在兩個引号'“'之間,也可以在單個特殊字元後加反斜杠'\':
John\@[email protected] (這是與上面帶有引号的字元串相同的位址)。
有效的電子郵件位址
(靈感來自https://en.wikipedia.org/wiki/Email_address#Examples和RFC 3696名稱檢查和轉換的應用技術:電子郵件位址的限制)
[email protected]
域(Domain)應該包含“.”,因為根域不能是電子郵件伺服器的位址。當然,對于大多數規則,也有一個例外:[email protected]。該域位址不是用于Internet,而是用于公司的内部網絡。
[email protected]
一個字母的local-part是可以的。
[email protected]
句點“.”字元遵循一些特殊的規則:它不能是local-part或domain-part的第一或的最後一個字母并不能有連續的2個點像“..”。
Gmail将“John.Doe”和“JohnDoe”視為相同的位址。如上所述,由接收電子郵件伺服器決定如何解釋其郵箱位址。但是,當使用電子郵件位址來辨別個人(例如登入頁面)時,就會出現問題。是否會假設John.Doe@ example.com和JohnDoe@ example.com是2個不同的人?
[email protected]
[email protected]
連字元'-'和下劃線'_'任何地方都可以接受
[email protected]
可能合法,但是所有電子郵件軟體都可以了解嗎?某些電子郵件伺服器将使用“John.Doe”作為實際郵箱名稱,并忽略“+”及其後的所有内容,直到“@”為止。
實際上,所有這些字元在local-part!#$%&'* +-/ =?^ _` . {| }〜中都是合法的。但并非所有電子郵件軟體都可以接受它們。O'[email protected]較差,一些電子郵件用戶端隻是将其發送到[email protected]。
顯示名稱
“<”和“>”字元不在上面的清單中,因為它們具有特殊含義,它們将“顯示名稱”與實際的“電子郵件位址”分開:
My Name <[email protected]>
顯示名稱隻能在尖括号中的電子郵件位址之前。它可以包含相同的字元,例如電子郵件位址和空格。
注釋
在上面的清單中括号'('還缺少')'。它們包含注釋:
Name(Comment1)<(Comment2)Name(Comment3)@(Comment4)Example.com(Comment5>(Comment2)
注釋放在圓括号中。注釋可以包含任何可列印的ASCII字元,但'(',')'和'\'除外。這嚴格按照RFC5322進行,但是我想很多電子郵件軟體都無法正确解釋它。如上所述,有些人甚至将其用作顯示名稱,這是錯誤的。如果可能的話,請勿使用注釋。
引号
" "@example.org
引号之間的空格是郵箱的名稱。在2個雙引号之間,幾乎沒有任何變化。這使驗證變得困難。
"john..doe"@example.org
帶雙引号的引号,不允許帶引号
Some\@[email protected]
第一個@應被視為一個簡單的文字,而不是作為控制字元從domain-part分隔local-part。
John\ [email protected]
空格隻允許被引用(在RFC的說法中,引用也意味着一個前導反斜杠'\'。
John.\\[email protected]
第一個反斜杠“\”使第二個反斜杠“\”成為普通字元。
一些看起來很奇怪的有效位址
"very.(),:;<>[]\".VERY.\"[email protected]\ \"very\".unusual"@strange.example.com
[email protected]
用于uucp郵件的分類主機路由
user%[email protected]
%通過example.org路由到了[email protected]
Domain-Part要求
domain-part是一個DNS主機名,由字母、數字、連字元和點組成。在極少數情況下,可以改用IP位址,并用方括号括起來:
[email protected][192.168.0.0]
[email protected][IPv6:2001:db8::1]
不使用ASCII字元(UTF8)
rfc6530,rfc6531,rfc6532指定在電子郵件軟體支援的情況下如何将任何UTF字元用于電子郵件位址。由于電子郵件通常是從伺服器轉發到另一台伺服器...,這很可能是這些伺服器之一不支援UTF8,并且向發件人傳回了一條錯誤消息,提示無法發送電子郵件。出于這個原因,盡管以下示例實際上是有效的位址,但是不要對電子郵件位址使用UTF8是更安全的:
Pelé@example.com
δοκιμή@παράδειγμα.δοκιμή
我買@屋企.香港
संपर्क@डाटामेल.भारतारत
尤其麻煩的是domain-part,因為必須從可能不支援UTF8的DNS伺服器中查找實際IP位址。是以,發明了PunyCode,它以純ASCII編碼UTF8,然後也可以由無UTF8域伺服器處理。但是您的電子郵件軟體是否支援Punycode?
如前所述,目标是使用不會引起麻煩的電子郵件位址。使用基于UTF8的位址會帶來麻煩。如果必須的話,請接受UTF8,但是如果不這樣做,您的生活會輕松得多。
長度限制
除了文法限制外,電子郵件位址還有長度限制。該限制最大為64個字元(UTF8位元組),local-part最大為255個字元(UTF8位元組),domain-part總長度為320個字元。
非法的電子郵件位址
如上所述,電子郵件位址有許多有效的結構。但是也有非法的:
Abc.example.com
沒有@字元
[email protected]@[email protected]
用引号引起來的字元串之外隻能有一個@,除非用引号引起來
[email protected]
任何地方都不允許雙點'..'
a"b(c)d,e:f;g<h>i[j\k][email protected]
此local-part中的特殊字元均不能使用引号引起來
just"not"[email protected]
用引号引起來的字元串必須用點分隔,或組成local-part的唯一進制素
123[email protected]example.com
local-part超過64個字元
推薦建議
- 如果使用者輸入的電子郵件位址看起來很奇怪,則向使用者發出警告。很可能是拼寫錯誤,但也可能隻是一個看起來很奇怪但有效的電子郵件位址。由使用者決定。
- 通過減少可輸入的字元集來幫助使用者限制可能犯的錯誤數量。如果可能,請避免使用UTF8。
編寫電子郵件驗證以正确識别所有合法和非法電子郵件位址非常困難,有人說幾乎是不可能的。即使有可能,也并不意味着該電子郵件位址确實有效。驗證的唯一方法是發送電子郵件并等待回複。是以,最好是使用一個相對簡單的驗證來警告使用者,如果某些東西看起來很奇怪,進而發現錯别字,但将最終決定權留給使用者。
使用代碼
<wwl:CheckedWindow x:Class="Samples.SampleWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wwl="clr-namespace:WpfWindowsLib;assembly=WpfWindowsLib"
SizeToContent="WidthAndHeight">
<StackPanel>
<Label Content="Name (required)"/>
<wwl:CheckedTextBox x:Name="NameTextBox" MinWidth="100" IsRequired="True"/>
<Label Content="Email (not required)"/>
<wwl:EmailTextBox x:Name="EmailTextBox" MinWidth="100"/>
<Button x:Name="SaveButton" Content="_Save"/>
</StackPanel>
</wwl:CheckedWindow>
顯示的上部視窗是帶有名稱TextBox的資料輸入視窗,使用者在儲存之前必須在其中輸入一些資料,以及EmailTextBox。TextBox需要一個名字,但使用者沒有輸入任何資料,這就是為什麼背景是卡其色。這也是禁用“儲存”按鈕的原因。使用者已輸入電子郵件位址。然後,使用者嘗試關閉視窗而不儲存資料。打開第二個警告視窗,“電子郵件TextBox”的背景變為淺綠色,以向使用者顯示哪些資料已更改。有關如何工作的詳細說明,請參閱我的文章“用于資料輸入的基本WPF視窗功能”。
在此螢幕快照中,使用者輸入了名稱。是以儲存按鈕被激活。使用者單擊“儲存”按鈕,但收到警告,因為該電子郵件位址看起來很奇怪(不是在domain-part中的“.”),然後可以決定是否應儲存該電子郵件位址或是否需要進一步編輯。
配置EmailTextBox
在許多情況下,您無需進行任何配置。您可能要在XAML中進行設定IsRequired,或者,如果使用者要編輯一些現有資料,則調用Initialise()傳遞現有電子郵件位址并将其isRequired作為後面代碼中的參數的電話。
執行個體屬性
可以為每個PhoneTextBox屬性分别設定一些屬性:
- IsRequired(DependencyProperty):是否需要使用者為該控件提供值?
- MaxLength (DependencyProperty):可以在文本框中手動輸入的最大字元數。
靜态特性
一些屬性适用于每個PhoneTextBox屬性,是以聲明為static:
- AsciiSpecialChars (string):電子郵件位址local-part中字母和數字之外的其他字元。預設值:“[email protected]_+”。要允許更多字元,請配置設定您自己的字元串或調用EmailTextBox.SetExtendedAsciiSpecialChars()或EmailTextBox.SetExtendedQuotedAsciiSpecialChars()。
- IsBlankAllowed:設定為true使用者是否應該能夠鍵入空白。
- IsInternationalCharSetAllowed:設定為true使用者是否應該能夠使用大于0x7F的Unicode字元。
- IsValidEmailChar(Func<char, bool>):被調用以驗證電子郵件位址local-part中是否允許使用者剛剛輸入的字元。如果要使用其他驗證,請配置設定自己的函數。
- IsValidDnsChar(Func<char, bool>):被調用以驗證電子郵件位址domain-part中是否允許使用者剛剛輸入的字元。如果要使用其他驗證,請配置設定自己的函數。
- IsValidEmail(Func<string, bool>):一旦鍵盤焦點離開EmailTextBox,就會被調用以驗證完整的電子郵件位址。如果要使用其他驗證,請配置設定自己的函數。
- ShowLooksStrangeWarning(Func<EmailTextBox, bool>):IsValidEmail 檢測到問題時被調用。如果您想以不同的方式顯示問題,請配置設定自己的函數。
擷取代碼
可從Github獲得最新版本:https://github.com/PeterHuberSg/WpfWindowsLib。
将所有内容下載下傳或克隆到您的PC,這為您提供了以下項目的解決方案WpfWindowsLib:
- WpfWindowsLib:(. Dll)要從您的其他解決方案中引用,包含EmailTextBox
- Samples:WPF Core應用程式顯示所有WpfWindowsLib 控件
- WpfWindowsLibTest:幾乎沒有WpfWindowsLib單元測試