/src/yolk-email.adb

http://github.com/ThomasLocke/yolk · Ada · 744 lines · 488 code · 149 blank · 107 comment · 17 complexity · 93e280971700100cc9cfbb4f633a51b4 MD5 · raw file

  1. -------------------------------------------------------------------------------
  2. -- --
  3. -- Copyright (C) 2010-, Thomas ¸cke --
  4. -- --
  5. -- This library is free software; you can redistribute it and/or modify --
  6. -- it under terms of the GNU General Public License as published by the --
  7. -- Free Software Foundation; either version 3, or (at your option) any --
  8. -- later version. This library is distributed in the hope that it will be --
  9. -- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of --
  10. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
  11. -- --
  12. -- As a special exception under Section 7 of GPL version 3, you are --
  13. -- granted additional permissions described in the GCC Runtime Library --
  14. -- Exception, version 3.1, as published by the Free Software Foundation. --
  15. -- --
  16. -- You should have received a copy of the GNU General Public License and --
  17. -- a copy of the GCC Runtime Library Exception along with this program; --
  18. -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
  19. -- <http://www.gnu.org/licenses/>. --
  20. -- --
  21. -------------------------------------------------------------------------------
  22. with Ada.Calendar;
  23. with Ada.Directories;
  24. with AWS.MIME;
  25. with AWS.Utils;
  26. with GNATCOLL.Email.Utils;
  27. with GNATCOLL.VFS;
  28. with Yolk.Utilities;
  29. package body Yolk.Email is
  30. procedure Build_Attachments
  31. (ES : in Structure;
  32. Email : in out GNATCOLL.Email.Message);
  33. -- Add attachments to Email.
  34. procedure Build_Bcc_Header
  35. (ES : in Structure;
  36. Email : in out GNATCOLL.Email.Message);
  37. -- Build the Bcc header and add it to Email.
  38. procedure Build_Cc_Header
  39. (ES : in Structure;
  40. Email : in out GNATCOLL.Email.Message);
  41. -- Build the Cc header and add it to Email.
  42. procedure Build_Content_Transfer_Encoding_Header
  43. (Charset : in Character_Set;
  44. Email : in out GNATCOLL.Email.Message);
  45. -- Build the Content-Transfer-Encoding header and add it to Email.
  46. procedure Build_Content_Type_Header
  47. (ES : in Structure;
  48. Email : in out GNATCOLL.Email.Message;
  49. Kind : in String);
  50. -- Build the Content-Type header and add it to Email.
  51. procedure Build_Custom_Headers
  52. (ES : in Structure;
  53. Email : in out GNATCOLL.Email.Message);
  54. -- Build the custom headers. Custom headers are usually things like
  55. -- User-Agent, Organization or X - headers.
  56. procedure Build_Date_Header
  57. (Email : in out GNATCOLL.Email.Message);
  58. -- Build the Date header and add it to Email.
  59. procedure Build_Email_Data
  60. (Header : in out GNATCOLL.Email.Header;
  61. List : in Email_Data_Container.Vector);
  62. -- Construct the actual content for the sender/recipient headers, such as
  63. -- To, Cc, Bcc, Reply-To and so on.
  64. procedure Build_From_Header
  65. (ES : in Structure;
  66. Email : in out GNATCOLL.Email.Message);
  67. -- Build the From header and add it to Email.
  68. procedure Build_General_Headers
  69. (ES : in Structure;
  70. Email : in out GNATCOLL.Email.Message);
  71. -- Add the general headers such as To, From, Date and so on, to the Email.
  72. procedure Build_MIME_Header
  73. (Email : in out GNATCOLL.Email.Message);
  74. -- Build the MIME-Version header and add it to Email.
  75. procedure Build_Reply_To_Header
  76. (ES : in Structure;
  77. Email : in out GNATCOLL.Email.Message);
  78. -- Build the Reply-To header and add it to Email.
  79. procedure Build_Sender_Header
  80. (ES : in Structure;
  81. Email : in out GNATCOLL.Email.Message);
  82. -- Build the Sender header and add it to Email.
  83. procedure Build_Subject_Header
  84. (ES : in Structure;
  85. Email : in out GNATCOLL.Email.Message);
  86. -- Build the Subject header and add it to Email.
  87. procedure Build_To_Header
  88. (ES : in Structure;
  89. Email : in out GNATCOLL.Email.Message);
  90. -- Build the To header and add it to Email.
  91. function To_Virtual_File
  92. (Item : in Attachment_Data)
  93. return GNATCOLL.VFS.Virtual_File;
  94. -- Convert an Attachment_Data.Path_To_File to a GNATCOLL.VFS Virtual_File.
  95. -- Exceptions:
  96. -- Attachment_File_Not_Found
  97. -------------------------
  98. -- Build_Attachments --
  99. -------------------------
  100. procedure Build_Attachments
  101. (ES : in Structure;
  102. Email : in out GNATCOLL.Email.Message)
  103. is
  104. List : Attachments_Container.Vector renames ES.Attachment_List;
  105. begin
  106. for i in List.First_Index .. List.Last_Index loop
  107. declare
  108. use GNATCOLL.VFS;
  109. Data : constant Attachment_Data := List.Element (i);
  110. File : constant Virtual_File := To_Virtual_File (Item => Data);
  111. begin
  112. Email.Attach (Path => File,
  113. MIME_Type => AWS.MIME.Content_Type
  114. (Filename => To_String (Data.Path_To_File)),
  115. Charset => Get_Charset (Data.Charset));
  116. end;
  117. end loop;
  118. end Build_Attachments;
  119. ------------------------
  120. -- Build_Bcc_Header --
  121. ------------------------
  122. procedure Build_Bcc_Header
  123. (ES : in Structure;
  124. Email : in out GNATCOLL.Email.Message)
  125. is
  126. begin
  127. if not ES.Bcc_List.Is_Empty then
  128. declare
  129. use GNATCOLL.Email;
  130. Bcc : Header := Create (Name => "Bcc",
  131. Value => "");
  132. begin
  133. Build_Email_Data (Header => Bcc,
  134. List => ES.Bcc_List);
  135. Email.Add_Header (H => Bcc);
  136. end;
  137. end if;
  138. end Build_Bcc_Header;
  139. -----------------------
  140. -- Build_Cc_Header --
  141. -----------------------
  142. procedure Build_Cc_Header
  143. (ES : in Structure;
  144. Email : in out GNATCOLL.Email.Message)
  145. is
  146. begin
  147. if not ES.Cc_List.Is_Empty then
  148. declare
  149. use GNATCOLL.Email;
  150. Cc : Header := Create (Name => "Cc",
  151. Value => "");
  152. begin
  153. Build_Email_Data (Header => Cc,
  154. List => ES.Cc_List);
  155. Email.Add_Header (H => Cc);
  156. end;
  157. end if;
  158. end Build_Cc_Header;
  159. ----------------------------------------------
  160. -- Build_Content_Transfer_Encoding_Header --
  161. ----------------------------------------------
  162. procedure Build_Content_Transfer_Encoding_Header
  163. (Charset : in Character_Set;
  164. Email : in out GNATCOLL.Email.Message)
  165. is
  166. use GNATCOLL.Email;
  167. CTE : Header;
  168. begin
  169. case Charset is
  170. when US_ASCII =>
  171. CTE := Create (Name => Content_Transfer_Encoding,
  172. Value => "7bit");
  173. when ISO_8859_1 .. Windows_1252 =>
  174. CTE := Create (Name => Content_Transfer_Encoding,
  175. Value => "quoted-printable");
  176. when UTF8 =>
  177. CTE := Create (Name => Content_Transfer_Encoding,
  178. Value => "quoted-printable");
  179. end case;
  180. Email.Add_Header (H => CTE);
  181. end Build_Content_Transfer_Encoding_Header;
  182. ---------------------------------
  183. -- Build_Content_Type_Header --
  184. ---------------------------------
  185. procedure Build_Content_Type_Header
  186. (ES : in Structure;
  187. Email : in out GNATCOLL.Email.Message;
  188. Kind : in String)
  189. is
  190. use GNATCOLL.Email;
  191. CT : Header;
  192. begin
  193. CT := Create (Name => Content_Type,
  194. Value => Kind);
  195. CT.Set_Param (Param_Name => "charset",
  196. Param_Value => Get_Charset (ES.Text_Part.Charset));
  197. Email.Add_Header (H => CT);
  198. end Build_Content_Type_Header;
  199. ----------------------------
  200. -- Build_Custom_Headers --
  201. ----------------------------
  202. procedure Build_Custom_Headers
  203. (ES : in Structure;
  204. Email : in out GNATCOLL.Email.Message)
  205. is
  206. use GNATCOLL.Email;
  207. Data : Header_Data;
  208. Custom : Header;
  209. List : Custom_Headers_Container.Vector renames ES.Custom_Headers;
  210. begin
  211. for i in List.First_Index .. List.Last_Index loop
  212. Data := List.Element (i);
  213. Custom := Create (Name => To_String (Data.Name),
  214. Value => To_String (Data.Value),
  215. Charset => Get_Charset (Data.Charset));
  216. Email.Add_Header (H => Custom);
  217. end loop;
  218. end Build_Custom_Headers;
  219. -------------------------
  220. -- Build_Date_Header --
  221. -------------------------
  222. procedure Build_Date_Header
  223. (Email : in out GNATCOLL.Email.Message)
  224. is
  225. use GNATCOLL.Email;
  226. use GNATCOLL.Email.Utils;
  227. Date : constant Header := Create
  228. (Name => "Date",
  229. Value => Format_Date (Date => Ada.Calendar.Clock));
  230. begin
  231. Email.Add_Header (H => Date);
  232. end Build_Date_Header;
  233. ------------------------
  234. -- Build_Email_Data --
  235. ------------------------
  236. procedure Build_Email_Data
  237. (Header : in out GNATCOLL.Email.Header;
  238. List : in Email_Data_Container.Vector)
  239. is
  240. use Yolk.Utilities;
  241. Data : Email_Data;
  242. begin
  243. for i in List.First_Index .. List.Last_Index loop
  244. Data := List.Element (i);
  245. if Is_Empty (Data.Address) then
  246. raise No_Address_Set;
  247. end if;
  248. if Data.Name = "" then
  249. Header.Append (Value => To_String (Data.Address));
  250. else
  251. Header.Append (Value => To_String (Data.Name),
  252. Charset => Get_Charset (Data.Charset));
  253. Header.Append (Value => " <" & To_String (Data.Address) & ">");
  254. end if;
  255. if i /= List.Last_Index then
  256. Header.Append (Value => ", ");
  257. end if;
  258. end loop;
  259. end Build_Email_Data;
  260. -------------------------
  261. -- Build_From_Header --
  262. -------------------------
  263. procedure Build_From_Header
  264. (ES : in Structure;
  265. Email : in out GNATCOLL.Email.Message)
  266. is
  267. use GNATCOLL.Email;
  268. From : Header := Create (Name => "From",
  269. Value => "");
  270. begin
  271. Build_Email_Data (Header => From,
  272. List => ES.From_List);
  273. Email.Add_Header (H => From);
  274. end Build_From_Header;
  275. -----------------------------
  276. -- Build_General_Headers --
  277. -----------------------------
  278. procedure Build_General_Headers
  279. (ES : in Structure;
  280. Email : in out GNATCOLL.Email.Message)
  281. is
  282. begin
  283. Build_Bcc_Header (ES => ES,
  284. Email => Email);
  285. Build_Cc_Header (ES => ES,
  286. Email => Email);
  287. Build_Custom_Headers (ES => ES,
  288. Email => Email);
  289. Build_Date_Header (Email => Email);
  290. Build_From_Header (ES => ES,
  291. Email => Email);
  292. Build_MIME_Header (Email => Email);
  293. Build_Reply_To_Header (ES => ES,
  294. Email => Email);
  295. Build_Sender_Header (ES => ES,
  296. Email => Email);
  297. Build_Subject_Header (ES => ES,
  298. Email => Email);
  299. Build_To_Header (ES => ES,
  300. Email => Email);
  301. end Build_General_Headers;
  302. -------------------------
  303. -- Build_MIME_Header --
  304. -------------------------
  305. procedure Build_MIME_Header
  306. (Email : in out GNATCOLL.Email.Message)
  307. is
  308. use GNATCOLL.Email;
  309. MIME : constant Header := Create (Name => MIME_Version,
  310. Value => "1.0");
  311. begin
  312. Email.Add_Header (H => MIME);
  313. end Build_MIME_Header;
  314. -----------------------------
  315. -- Build_Reply_To_Header --
  316. -----------------------------
  317. procedure Build_Reply_To_Header
  318. (ES : in Structure;
  319. Email : in out GNATCOLL.Email.Message)
  320. is
  321. begin
  322. if not ES.Reply_To_List.Is_Empty then
  323. declare
  324. use GNATCOLL.Email;
  325. Reply_To : Header := Create (Name => "Reply-To",
  326. Value => "");
  327. begin
  328. Build_Email_Data (Header => Reply_To,
  329. List => ES.Reply_To_List);
  330. Email.Add_Header (H => Reply_To);
  331. end;
  332. end if;
  333. end Build_Reply_To_Header;
  334. ---------------------------
  335. -- Build_Sender_Header --
  336. ---------------------------
  337. procedure Build_Sender_Header
  338. (ES : in Structure;
  339. Email : in out GNATCOLL.Email.Message)
  340. is
  341. begin
  342. if ES.Sender.Address /= Null_Unbounded_String then
  343. declare
  344. use GNATCOLL.Email;
  345. Sender : Header;
  346. begin
  347. if ES.Sender.Name = "" then
  348. Sender := Create (Name => "Sender",
  349. Value => To_String (ES.Sender.Address),
  350. Charset => Get_Charset (ES.Sender.Charset));
  351. else
  352. Sender := Create (Name => "Sender",
  353. Value => To_String (ES.Sender.Name),
  354. Charset => Get_Charset (ES.Sender.Charset));
  355. Sender.Append
  356. (Value => " <" & To_String (ES.Sender.Address) & ">");
  357. end if;
  358. Email.Add_Header (H => Sender);
  359. end;
  360. else
  361. if ES.From_List.Length > 1 then
  362. raise No_Sender_Set_With_Multiple_From;
  363. end if;
  364. end if;
  365. end Build_Sender_Header;
  366. ----------------------------
  367. -- Build_Subject_Header --
  368. ----------------------------
  369. procedure Build_Subject_Header
  370. (ES : in Structure;
  371. Email : in out GNATCOLL.Email.Message)
  372. is
  373. use GNATCOLL.Email;
  374. Subject : constant Header := Create
  375. (Name => "Subject",
  376. Value => To_String (ES.Subject.Content),
  377. Charset => Get_Charset (ES.Subject.Charset));
  378. begin
  379. Email.Add_Header (H => Subject);
  380. end Build_Subject_Header;
  381. -------------------------
  382. -- Build_To_Header --
  383. -------------------------
  384. procedure Build_To_Header
  385. (ES : in Structure;
  386. Email : in out GNATCOLL.Email.Message)
  387. is
  388. use GNATCOLL.Email;
  389. To : Header := Create (Name => "To",
  390. Value => "");
  391. begin
  392. Build_Email_Data (Header => To,
  393. List => ES.To_List);
  394. Email.Add_Header (H => To);
  395. end Build_To_Header;
  396. ------------------------------------
  397. -- Generate_Text_And_HTML_Email --
  398. ------------------------------------
  399. procedure Generate_Text_And_HTML_Email
  400. (ES : in out Structure)
  401. is
  402. use GNATCOLL.Email;
  403. Email : Message := New_Message (Multipart_Alternative);
  404. HTML_Payload : Message := New_Message (Text_Html);
  405. Text_Payload : Message := New_Message (Text_Plain);
  406. begin
  407. Email.Set_Boundary (Boundary => AWS.Utils.Random_String (16));
  408. Text_Payload.Set_Text_Payload
  409. (Payload => To_String (ES.Text_Part.Content),
  410. Charset => Get_Charset (ES.Text_Part.Charset));
  411. Text_Payload.Delete_Headers (Name => "");
  412. Build_Content_Transfer_Encoding_Header (Charset => ES.Text_Part.Charset,
  413. Email => Text_Payload);
  414. Build_Content_Type_Header (ES => ES,
  415. Email => Text_Payload,
  416. Kind => Text_Plain);
  417. HTML_Payload.Set_Text_Payload
  418. (Payload => To_String (ES.HTML_Part.Content),
  419. Charset => Get_Charset (ES.HTML_Part.Charset));
  420. HTML_Payload.Delete_Headers (Name => "");
  421. Build_Content_Transfer_Encoding_Header (Charset => ES.HTML_Part.Charset,
  422. Email => HTML_Payload);
  423. Build_Content_Type_Header (ES => ES,
  424. Email => HTML_Payload,
  425. Kind => Text_Html);
  426. Email.Add_Payload (Payload => Text_Payload,
  427. First => True);
  428. Email.Add_Payload (Payload => HTML_Payload,
  429. First => False);
  430. Email.Set_Preamble
  431. (Preamble => "This is a multi-part message in MIME format.");
  432. Build_General_Headers (ES => ES,
  433. Email => Email);
  434. ES.Composed_Message := Email;
  435. end Generate_Text_And_HTML_Email;
  436. ----------------------------------------------------
  437. -- Generate_Text_And_HTML_With_Attachment_Email --
  438. ----------------------------------------------------
  439. procedure Generate_Text_And_HTML_With_Attachment_Email
  440. (ES : in out Structure)
  441. is
  442. use GNATCOLL.Email;
  443. Email_Alt : Message := New_Message (Multipart_Alternative);
  444. Email_Mixed : Message := New_Message (Multipart_Mixed);
  445. HTML_Payload : Message := New_Message (Text_Html);
  446. Text_Payload : Message := New_Message (Text_Plain);
  447. begin
  448. Email_Alt.Set_Boundary (Boundary => AWS.Utils.Random_String (16));
  449. Email_Mixed.Set_Boundary (Boundary => AWS.Utils.Random_String (16));
  450. Text_Payload.Set_Text_Payload
  451. (Payload => To_String (ES.Text_Part.Content),
  452. Charset => Get_Charset (ES.Text_Part.Charset));
  453. Text_Payload.Delete_Headers (Name => "");
  454. Build_Content_Transfer_Encoding_Header (Charset => ES.Text_Part.Charset,
  455. Email => Text_Payload);
  456. Build_Content_Type_Header (ES => ES,
  457. Email => Text_Payload,
  458. Kind => Text_Plain);
  459. HTML_Payload.Set_Text_Payload
  460. (Payload => To_String (ES.HTML_Part.Content),
  461. Charset => Get_Charset (ES.HTML_Part.Charset));
  462. HTML_Payload.Delete_Headers (Name => "");
  463. Build_Content_Transfer_Encoding_Header (Charset => ES.HTML_Part.Charset,
  464. Email => HTML_Payload);
  465. Build_Content_Type_Header (ES => ES,
  466. Email => HTML_Payload,
  467. Kind => Text_Html);
  468. Email_Alt.Add_Payload (Payload => Text_Payload,
  469. First => True);
  470. Email_Alt.Add_Payload (Payload => HTML_Payload,
  471. First => False);
  472. Email_Mixed.Add_Payload (Payload => Email_Alt,
  473. First => True);
  474. Build_Attachments (ES => ES,
  475. Email => Email_Mixed);
  476. Email_Mixed.Set_Preamble
  477. (Preamble => "This is a multi-part message in MIME format.");
  478. Build_General_Headers (ES => ES,
  479. Email => Email_Mixed);
  480. ES.Composed_Message := Email_Mixed;
  481. end Generate_Text_And_HTML_With_Attachment_Email;
  482. ---------------------------
  483. -- Generate_Text_Email --
  484. ---------------------------
  485. procedure Generate_Text_Email
  486. (ES : in out Structure)
  487. is
  488. use GNATCOLL.Email;
  489. Email : Message := New_Message (MIME_Type => Text_Plain);
  490. begin
  491. Email.Set_Text_Payload
  492. (Payload => To_String (ES.Text_Part.Content),
  493. Charset => Get_Charset (ES.Text_Part.Charset));
  494. Email.Delete_Headers (Name => "");
  495. Build_General_Headers (ES => ES,
  496. Email => Email);
  497. Build_Content_Transfer_Encoding_Header (Charset => ES.Text_Part.Charset,
  498. Email => Email);
  499. Build_Content_Type_Header (ES => ES,
  500. Email => Email,
  501. Kind => Text_Plain);
  502. ES.Composed_Message := Email;
  503. end Generate_Text_Email;
  504. -------------------------------------------
  505. -- Generate_Text_With_Attachment_Email --
  506. -------------------------------------------
  507. procedure Generate_Text_With_Attachment_Email
  508. (ES : in out Structure)
  509. is
  510. use GNATCOLL.Email;
  511. Email : Message := New_Message (MIME_Type => Multipart_Mixed);
  512. Text_Payload : Message := New_Message (MIME_Type => Text_Plain);
  513. begin
  514. Email.Set_Boundary (Boundary => AWS.Utils.Random_String (16));
  515. Text_Payload.Set_Text_Payload
  516. (Payload => To_String (ES.Text_Part.Content),
  517. Charset => Get_Charset (ES.Text_Part.Charset));
  518. Text_Payload.Delete_Headers (Name => "");
  519. Build_Content_Transfer_Encoding_Header (Charset => ES.Text_Part.Charset,
  520. Email => Text_Payload);
  521. Build_Content_Type_Header (ES => ES,
  522. Email => Text_Payload,
  523. Kind => Text_Plain);
  524. Email.Add_Payload (Payload => Text_Payload,
  525. First => True);
  526. Build_Attachments (ES => ES,
  527. Email => Email);
  528. Email.Set_Preamble
  529. (Preamble => "This is a multi-part message in MIME format.");
  530. Build_General_Headers (ES => ES,
  531. Email => Email);
  532. ES.Composed_Message := Email;
  533. end Generate_Text_With_Attachment_Email;
  534. -------------------
  535. -- Get_Charset --
  536. -------------------
  537. function Get_Charset
  538. (Charset : in Character_Set)
  539. return String
  540. is
  541. begin
  542. case Charset is
  543. when US_ASCII => return GNATCOLL.Email.Charset_US_ASCII;
  544. when ISO_8859_1 => return GNATCOLL.Email.Charset_ISO_8859_1;
  545. when ISO_8859_2 => return GNATCOLL.Email.Charset_ISO_8859_2;
  546. when ISO_8859_3 => return GNATCOLL.Email.Charset_ISO_8859_3;
  547. when ISO_8859_4 => return GNATCOLL.Email.Charset_ISO_8859_4;
  548. when ISO_8859_9 => return GNATCOLL.Email.Charset_ISO_8859_9;
  549. when ISO_8859_10 => return GNATCOLL.Email.Charset_ISO_8859_10;
  550. when ISO_8859_13 => return GNATCOLL.Email.Charset_ISO_8859_13;
  551. when ISO_8859_14 => return GNATCOLL.Email.Charset_ISO_8859_14;
  552. when ISO_8859_15 => return GNATCOLL.Email.Charset_ISO_8859_15;
  553. when Windows_1252 => return GNATCOLL.Email.Charset_Windows_1252;
  554. when UTF8 => return GNATCOLL.Email.Charset_UTF_8;
  555. end case;
  556. end Get_Charset;
  557. -------------------------
  558. -- Set_Type_Of_Email --
  559. -------------------------
  560. procedure Set_Type_Of_Email
  561. (ES : in out Structure)
  562. is
  563. begin
  564. if not ES.Has_Text_Part then
  565. ES.Text_Part.Content := U ("");
  566. end if;
  567. ES.Type_Of_Email := Text;
  568. if ES.Has_HTML_Part then
  569. ES.Type_Of_Email := Text_And_HTML;
  570. end if;
  571. if ES.Has_Attachment then
  572. if ES.Type_Of_Email = Text then
  573. ES.Type_Of_Email := Text_With_Attachment;
  574. elsif ES.Type_Of_Email = Text_And_HTML then
  575. ES.Type_Of_Email := Text_And_HTML_With_Attachment;
  576. end if;
  577. end if;
  578. end Set_Type_Of_Email;
  579. -----------------------
  580. -- To_Virtual_File --
  581. -----------------------
  582. function To_Virtual_File
  583. (Item : in Attachment_Data)
  584. return GNATCOLL.VFS.Virtual_File
  585. is
  586. use Ada.Directories;
  587. use GNATCOLL.VFS;
  588. Path_To_File : constant String := To_String (Item.Path_To_File);
  589. begin
  590. if not Exists (Path_To_File) then
  591. raise Attachment_File_Not_Found;
  592. end if;
  593. return Locate_On_Path (Filesystem_String (Path_To_File));
  594. end To_Virtual_File;
  595. end Yolk.Email;