mimemess.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 002.005.002 |
  3. |==============================================================================|
  4. | Content: MIME message object |
  5. |==============================================================================|
  6. | Copyright (c)1999-2006, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c)2000-2006. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): |
  40. |==============================================================================|
  41. | History: see HISTORY.HTM From distribution package |
  42. | (Found at URL: http://www.ararat.cz/synapse/) |
  43. |==============================================================================}
  44. {:@abstract(MIME message handling)
  45. Classes for easy handling with e-mail message.
  46. }
  47. {$IFDEF FPC}
  48. {$MODE DELPHI}
  49. {$ENDIF}
  50. {$H+}
  51. unit mimemess;
  52. interface
  53. uses
  54. Classes, SysUtils,
  55. mimepart, synachar, synautil, mimeinln;
  56. type
  57. {:Possible values for message priority}
  58. TMessPriority = (MP_unknown, MP_low, MP_normal, MP_high);
  59. {:@abstract(Object for basic e-mail header fields.)}
  60. TMessHeader = class(TObject)
  61. private
  62. FFrom: string;
  63. FToList: TStringList;
  64. FCCList: TStringList;
  65. FSubject: string;
  66. FOrganization: string;
  67. FCustomHeaders: TStringList;
  68. FDate: TDateTime;
  69. FXMailer: string;
  70. FCharsetCode: TMimeChar;
  71. FReplyTo: string;
  72. FMessageID: string;
  73. FPriority: TMessPriority;
  74. Fpri: TMessPriority;
  75. Fxpri: TMessPriority;
  76. Fxmspri: TMessPriority;
  77. protected
  78. function ParsePriority(value: string): TMessPriority;
  79. function DecodeHeader(value: string): boolean; virtual;
  80. public
  81. constructor Create; virtual;
  82. destructor Destroy; override;
  83. {:Clears all data fields.}
  84. procedure Clear; virtual;
  85. {Add headers from from this object to Value.}
  86. procedure EncodeHeaders(const Value: TStrings); virtual;
  87. {:Parse header from Value to this object.}
  88. procedure DecodeHeaders(const Value: TStrings);
  89. {:Try find specific header in CustomHeader. Search is case insensitive.
  90. This is good for reading any non-parsed header.}
  91. function FindHeader(Value: string): string;
  92. {:Try find specific headers in CustomHeader. This metod is for repeatly used
  93. headers like 'received' header, etc. Search is case insensitive.
  94. This is good for reading ano non-parsed header.}
  95. procedure FindHeaderList(Value: string; const HeaderList: TStrings);
  96. published
  97. {:Sender of message.}
  98. property From: string read FFrom Write FFrom;
  99. {:Stringlist with receivers of message. (one per line)}
  100. property ToList: TStringList read FToList;
  101. {:Stringlist with Carbon Copy receivers of message. (one per line)}
  102. property CCList: TStringList read FCCList;
  103. {:Subject of message.}
  104. property Subject: string read FSubject Write FSubject;
  105. {:Organization string.}
  106. property Organization: string read FOrganization Write FOrganization;
  107. {:After decoding contains all headers lines witch not have parsed to any
  108. other structures in this object. It mean: this conatins all other headers
  109. except:
  110. X-MAILER, FROM, SUBJECT, ORGANIZATION, TO, CC, DATE, MIME-VERSION,
  111. CONTENT-TYPE, CONTENT-DESCRIPTION, CONTENT-DISPOSITION, CONTENT-ID,
  112. CONTENT-TRANSFER-ENCODING, REPLY-TO, MESSAGE-ID, X-MSMAIL-PRIORITY,
  113. X-PRIORITY, PRIORITY
  114. When you encode headers, all this lines is added as headers. Be carefull
  115. for duplicites!}
  116. property CustomHeaders: TStringList read FCustomHeaders;
  117. {:Date and time of message.}
  118. property Date: TDateTime read FDate Write FDate;
  119. {:Mailer identification.}
  120. property XMailer: string read FXMailer Write FXMailer;
  121. {:Address for replies}
  122. property ReplyTo: string read FReplyTo Write FReplyTo;
  123. {:message indetifier}
  124. property MessageID: string read FMessageID Write FMessageID;
  125. {:message priority}
  126. property Priority: TMessPriority read FPriority Write FPriority;
  127. {:Specify base charset. By default is used system charset.}
  128. property CharsetCode: TMimeChar read FCharsetCode Write FCharsetCode;
  129. end;
  130. TMessHeaderClass = class of TMessHeader;
  131. {:@abstract(Object for handling of e-mail message.)}
  132. TMimeMess = class(TObject)
  133. private
  134. FMessagePart: TMimePart;
  135. FLines: TStringList;
  136. FHeader: TMessHeader;
  137. public
  138. constructor Create;
  139. {:create this object and assign your own descendant of @link(TMessHeader)
  140. object to @link(header) property. So, you can create your own message
  141. headers parser and use it by this object.}
  142. constructor CreateAltHeaders(HeadClass: TMessHeaderClass);
  143. destructor Destroy; override;
  144. {:Reset component to default state.}
  145. procedure Clear; virtual;
  146. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  147. then set as PartParent @NIL value. If you need set more then one subpart,
  148. you must have PartParent of multipart type!}
  149. function AddPart(const PartParent: TMimePart): TMimePart;
  150. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  151. then set as PartParent @NIL value. If you need set more then 1 subpart, you
  152. must have PartParent of multipart type!
  153. This part is marked as multipart with secondary MIME type specified by
  154. MultipartType parameter. (typical value is 'mixed')
  155. This part can be used as PartParent for another parts (include next
  156. multipart). If you need only one part, then you not need Multipart part.}
  157. function AddPartMultipart(const MultipartType: String; const PartParent: TMimePart): TMimePart;
  158. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  159. then set as PartParent @NIL value. If you need set more then 1 subpart, you
  160. must have PartParent of multipart type!
  161. After creation of part set type to text part and set all necessary
  162. properties. Content of part is readed from value stringlist.}
  163. function AddPartText(const Value: TStrings; const PartParent: TMimePart): TMimepart;
  164. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  165. then set as PartParent @NIL value. If you need set more then 1 subpart, you
  166. must have PartParent of multipart type!
  167. After creation of part set type to text part and set all necessary
  168. properties. Content of part is readed from value stringlist. You can select
  169. your charset and your encoding type. If Raw is @true, then it not doing
  170. charset conversion!}
  171. function AddPartTextEx(const Value: TStrings; const PartParent: TMimePart;
  172. PartCharset: TMimeChar; Raw: Boolean; PartEncoding: TMimeEncoding): TMimepart;
  173. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  174. then set as PartParent @NIL value. If you need set more then 1 subpart, you
  175. must have PartParent of multipart type!
  176. After creation of part set type to text part to HTML type and set all
  177. necessary properties. Content of HTML part is readed from Value stringlist.}
  178. function AddPartHTML(const Value: TStrings; const PartParent: TMimePart): TMimepart;
  179. {:Same as @link(AddPartText), but content is readed from file}
  180. function AddPartTextFromFile(const FileName: String; const PartParent: TMimePart): TMimepart;
  181. {:Same as @link(AddPartHTML), but content is readed from file}
  182. function AddPartHTMLFromFile(const FileName: String; const PartParent: TMimePart): TMimepart;
  183. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  184. then set as PartParent @NIL value. If you need set more then 1 subpart,
  185. you must have PartParent of multipart type!
  186. After creation of part set type to binary and set all necessary properties.
  187. MIME primary and secondary types defined automaticly by filename extension.
  188. Content of binary part is readed from Stream. This binary part is encoded
  189. as file attachment.}
  190. function AddPartBinary(const Stream: TStream; const FileName: string; const PartParent: TMimePart): TMimepart;
  191. {:Same as @link(AddPartBinary), but content is readed from file}
  192. function AddPartBinaryFromFile(const FileName: string; const PartParent: TMimePart): TMimepart;
  193. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  194. then set as PartParent @NIL value. If you need set more then 1 subpart, you
  195. must have PartParent of multipart type!
  196. After creation of part set type to binary and set all necessary properties.
  197. MIME primary and secondary types defined automaticly by filename extension.
  198. Content of binary part is readed from Stream.
  199. This binary part is encoded as inline data with given Conten ID (cid).
  200. Content ID can be used as reference ID in HTML source in HTML part.}
  201. function AddPartHTMLBinary(const Stream: TStream; const FileName, Cid: string; const PartParent: TMimePart): TMimepart;
  202. {:Same as @link(AddPartHTMLBinary), but content is readed from file}
  203. function AddPartHTMLBinaryFromFile(const FileName, Cid: string; const PartParent: TMimePart): TMimepart;
  204. {:Add MIME part as subpart of PartParent. If you need set root MIME part,
  205. then set as PartParent @NIL value. If you need set more then 1 subpart, you
  206. must have PartParent of multipart type!
  207. After creation of part set type to message and set all necessary properties.
  208. MIME primary and secondary types are setted to 'message/rfc822'.
  209. Content of raw RFC-822 message is readed from Stream.}
  210. function AddPartMess(const Value: TStrings; const PartParent: TMimePart): TMimepart;
  211. {:Same as @link(AddPartMess), but content is readed from file}
  212. function AddPartMessFromFile(const FileName: string; const PartParent: TMimePart): TMimepart;
  213. {:Compose message from @link(MessagePart) to @link(Lines). Headers from
  214. @link(Header) object is added also.}
  215. procedure EncodeMessage;
  216. {:Decode message from @link(Lines) to @link(MessagePart). Massage headers
  217. are parsed into @link(Header) object.}
  218. procedure DecodeMessage;
  219. published
  220. {:@link(TMimePart) object with decoded MIME message. This object can handle
  221. any number of nested @link(TMimePart) objects itself. It is used for handle
  222. any tree of MIME subparts.}
  223. property MessagePart: TMimePart read FMessagePart;
  224. {:Raw MIME encoded message.}
  225. property Lines: TStringList read FLines;
  226. {:Object for e-mail header fields. This object is created automaticly.
  227. Do not free this object!}
  228. property Header: TMessHeader read FHeader;
  229. end;
  230. implementation
  231. {==============================================================================}
  232. constructor TMessHeader.Create;
  233. begin
  234. inherited Create;
  235. FToList := TStringList.Create;
  236. FCCList := TStringList.Create;
  237. FCustomHeaders := TStringList.Create;
  238. FCharsetCode := GetCurCP;
  239. end;
  240. destructor TMessHeader.Destroy;
  241. begin
  242. FCustomHeaders.Free;
  243. FCCList.Free;
  244. FToList.Free;
  245. inherited Destroy;
  246. end;
  247. {==============================================================================}
  248. procedure TMessHeader.Clear;
  249. begin
  250. FFrom := '';
  251. FToList.Clear;
  252. FCCList.Clear;
  253. FSubject := '';
  254. FOrganization := '';
  255. FCustomHeaders.Clear;
  256. FDate := 0;
  257. FXMailer := '';
  258. FReplyTo := '';
  259. FMessageID := '';
  260. FPriority := MP_unknown;
  261. end;
  262. procedure TMessHeader.EncodeHeaders(const Value: TStrings);
  263. var
  264. n: Integer;
  265. s: string;
  266. begin
  267. if FDate = 0 then
  268. FDate := Now;
  269. for n := FCustomHeaders.Count - 1 downto 0 do
  270. if FCustomHeaders[n] <> '' then
  271. Value.Insert(0, FCustomHeaders[n]);
  272. if FPriority <> MP_unknown then
  273. case FPriority of
  274. MP_high:
  275. begin
  276. Value.Insert(0, 'X-MSMAIL-Priority: High');
  277. Value.Insert(0, 'X-Priority: 1');
  278. Value.Insert(0, 'Priority: urgent');
  279. end;
  280. MP_low:
  281. begin
  282. Value.Insert(0, 'X-MSMAIL-Priority: low');
  283. Value.Insert(0, 'X-Priority: 5');
  284. Value.Insert(0, 'Priority: non-urgent');
  285. end;
  286. end;
  287. if FReplyTo <> '' then
  288. Value.Insert(0, 'Reply-To: ' + GetEmailAddr(FReplyTo));
  289. if FMessageID <> '' then
  290. Value.Insert(0, 'Message-ID: <' + trim(FMessageID) + '>');
  291. if FXMailer = '' then
  292. Value.Insert(0, 'X-mailer: Synapse - Pascal TCP/IP library by Lukas Gebauer')
  293. else
  294. Value.Insert(0, 'X-mailer: ' + FXMailer);
  295. Value.Insert(0, 'MIME-Version: 1.0 (produced by Synapse)');
  296. if FOrganization <> '' then
  297. Value.Insert(0, 'Organization: ' + InlineCodeEx(FOrganization, FCharsetCode));
  298. s := '';
  299. for n := 0 to FCCList.Count - 1 do
  300. if s = '' then
  301. s := InlineEmailEx(FCCList[n], FCharsetCode)
  302. else
  303. s := s + ', ' + InlineEmailEx(FCCList[n], FCharsetCode);
  304. if s <> '' then
  305. Value.Insert(0, 'CC: ' + s);
  306. Value.Insert(0, 'Date: ' + Rfc822DateTime(FDate));
  307. if FSubject <> '' then
  308. Value.Insert(0, 'Subject: ' + InlineCodeEx(FSubject, FCharsetCode));
  309. s := '';
  310. for n := 0 to FToList.Count - 1 do
  311. if s = '' then
  312. s := InlineEmailEx(FToList[n], FCharsetCode)
  313. else
  314. s := s + ', ' + InlineEmailEx(FToList[n], FCharsetCode);
  315. if s <> '' then
  316. Value.Insert(0, 'To: ' + s);
  317. Value.Insert(0, 'From: ' + InlineEmailEx(FFrom, FCharsetCode));
  318. end;
  319. function TMessHeader.ParsePriority(value: string): TMessPriority;
  320. var
  321. s: string;
  322. x: integer;
  323. begin
  324. Result := MP_unknown;
  325. s := Trim(separateright(value, ':'));
  326. s := Separateleft(s, ' ');
  327. x := StrToIntDef(s, -1);
  328. if x >= 0 then
  329. case x of
  330. 1, 2:
  331. Result := MP_High;
  332. 3:
  333. Result := MP_Normal;
  334. 4, 5:
  335. Result := MP_Low;
  336. end
  337. else
  338. begin
  339. s := lowercase(s);
  340. if (s = 'urgent') or (s = 'high') or (s = 'highest') then
  341. Result := MP_High;
  342. if (s = 'normal') or (s = 'medium') then
  343. Result := MP_Normal;
  344. if (s = 'low') or (s = 'lowest')
  345. or (s = 'no-priority') or (s = 'non-urgent') then
  346. Result := MP_Low;
  347. end;
  348. end;
  349. function TMessHeader.DecodeHeader(value: string): boolean;
  350. var
  351. s, t: string;
  352. cp: TMimeChar;
  353. begin
  354. Result := True;
  355. cp := FCharsetCode;
  356. s := uppercase(value);
  357. if Pos('X-MAILER:', s) = 1 then
  358. begin
  359. FXMailer := Trim(SeparateRight(Value, ':'));
  360. Exit;
  361. end;
  362. if Pos('FROM:', s) = 1 then
  363. begin
  364. FFrom := InlineDecode(Trim(SeparateRight(Value, ':')), cp);
  365. Exit;
  366. end;
  367. if Pos('SUBJECT:', s) = 1 then
  368. begin
  369. FSubject := InlineDecode(Trim(SeparateRight(Value, ':')), cp);
  370. Exit;
  371. end;
  372. if Pos('ORGANIZATION:', s) = 1 then
  373. begin
  374. FOrganization := InlineDecode(Trim(SeparateRight(Value, ':')), cp);
  375. Exit;
  376. end;
  377. if Pos('TO:', s) = 1 then
  378. begin
  379. s := Trim(SeparateRight(Value, ':'));
  380. repeat
  381. t := InlineDecode(Trim(FetchEx(s, ',', '"')), cp);
  382. if t <> '' then
  383. FToList.Add(t);
  384. until s = '';
  385. Exit;
  386. end;
  387. if Pos('CC:', s) = 1 then
  388. begin
  389. s := Trim(SeparateRight(Value, ':'));
  390. repeat
  391. t := InlineDecode(Trim(FetchEx(s, ',', '"')), cp);
  392. if t <> '' then
  393. FCCList.Add(t);
  394. until s = '';
  395. Exit;
  396. end;
  397. if Pos('DATE:', s) = 1 then
  398. begin
  399. FDate := DecodeRfcDateTime(Trim(SeparateRight(Value, ':')));
  400. Exit;
  401. end;
  402. if Pos('REPLY-TO:', s) = 1 then
  403. begin
  404. FReplyTo := InlineDecode(Trim(SeparateRight(Value, ':')), cp);
  405. Exit;
  406. end;
  407. if Pos('MESSAGE-ID:', s) = 1 then
  408. begin
  409. FMessageID := GetEmailAddr(Trim(SeparateRight(Value, ':')));
  410. Exit;
  411. end;
  412. if Pos('PRIORITY:', s) = 1 then
  413. begin
  414. FPri := ParsePriority(value);
  415. Exit;
  416. end;
  417. if Pos('X-PRIORITY:', s) = 1 then
  418. begin
  419. FXPri := ParsePriority(value);
  420. Exit;
  421. end;
  422. if Pos('X-MSMAIL-PRIORITY:', s) = 1 then
  423. begin
  424. FXmsPri := ParsePriority(value);
  425. Exit;
  426. end;
  427. if Pos('MIME-VERSION:', s) = 1 then
  428. Exit;
  429. if Pos('CONTENT-TYPE:', s) = 1 then
  430. Exit;
  431. if Pos('CONTENT-DESCRIPTION:', s) = 1 then
  432. Exit;
  433. if Pos('CONTENT-DISPOSITION:', s) = 1 then
  434. Exit;
  435. if Pos('CONTENT-ID:', s) = 1 then
  436. Exit;
  437. if Pos('CONTENT-TRANSFER-ENCODING:', s) = 1 then
  438. Exit;
  439. Result := False;
  440. end;
  441. procedure TMessHeader.DecodeHeaders(const Value: TStrings);
  442. var
  443. s: string;
  444. x: Integer;
  445. begin
  446. Clear;
  447. Fpri := MP_unknown;
  448. Fxpri := MP_unknown;
  449. Fxmspri := MP_unknown;
  450. x := 0;
  451. while Value.Count > x do
  452. begin
  453. s := NormalizeHeader(Value, x);
  454. if s = '' then
  455. Break;
  456. if not DecodeHeader(s) then
  457. FCustomHeaders.Add(s);
  458. end;
  459. if Fpri <> MP_unknown then
  460. FPriority := Fpri
  461. else
  462. if Fxpri <> MP_unknown then
  463. FPriority := Fxpri
  464. else
  465. if Fxmspri <> MP_unknown then
  466. FPriority := Fxmspri
  467. end;
  468. function TMessHeader.FindHeader(Value: string): string;
  469. var
  470. n: integer;
  471. begin
  472. Result := '';
  473. for n := 0 to FCustomHeaders.Count - 1 do
  474. if Pos(UpperCase(Value), UpperCase(FCustomHeaders[n])) = 1 then
  475. begin
  476. Result := Trim(SeparateRight(FCustomHeaders[n], ':'));
  477. break;
  478. end;
  479. end;
  480. procedure TMessHeader.FindHeaderList(Value: string; const HeaderList: TStrings);
  481. var
  482. n: integer;
  483. begin
  484. HeaderList.Clear;
  485. for n := 0 to FCustomHeaders.Count - 1 do
  486. if Pos(UpperCase(Value), UpperCase(FCustomHeaders[n])) = 1 then
  487. begin
  488. HeaderList.Add(Trim(SeparateRight(FCustomHeaders[n], ':')));
  489. end;
  490. end;
  491. {==============================================================================}
  492. constructor TMimeMess.Create;
  493. begin
  494. CreateAltHeaders(TMessHeader);
  495. end;
  496. constructor TMimeMess.CreateAltHeaders(HeadClass: TMessHeaderClass);
  497. begin
  498. inherited Create;
  499. FMessagePart := TMimePart.Create;
  500. FLines := TStringList.Create;
  501. FHeader := HeadClass.Create;
  502. end;
  503. destructor TMimeMess.Destroy;
  504. begin
  505. FMessagePart.Free;
  506. FHeader.Free;
  507. FLines.Free;
  508. inherited Destroy;
  509. end;
  510. {==============================================================================}
  511. procedure TMimeMess.Clear;
  512. begin
  513. FMessagePart.Clear;
  514. FLines.Clear;
  515. FHeader.Clear;
  516. end;
  517. {==============================================================================}
  518. function TMimeMess.AddPart(const PartParent: TMimePart): TMimePart;
  519. begin
  520. if PartParent = nil then
  521. Result := FMessagePart
  522. else
  523. Result := PartParent.AddSubPart;
  524. Result.Clear;
  525. end;
  526. {==============================================================================}
  527. function TMimeMess.AddPartMultipart(const MultipartType: String; const PartParent: TMimePart): TMimePart;
  528. begin
  529. Result := AddPart(PartParent);
  530. with Result do
  531. begin
  532. Primary := 'Multipart';
  533. Secondary := MultipartType;
  534. Description := 'Multipart message';
  535. Boundary := GenerateBoundary;
  536. EncodePartHeader;
  537. end;
  538. end;
  539. function TMimeMess.AddPartText(const Value: TStrings; const PartParent: TMimePart): TMimepart;
  540. begin
  541. Result := AddPart(PartParent);
  542. with Result do
  543. begin
  544. Value.SaveToStream(DecodedLines);
  545. Primary := 'text';
  546. Secondary := 'plain';
  547. Description := 'Message text';
  548. Disposition := 'inline';
  549. CharsetCode := IdealCharsetCoding(Value.Text, TargetCharset, IdealCharsets);
  550. EncodingCode := ME_QUOTED_PRINTABLE;
  551. EncodePart;
  552. EncodePartHeader;
  553. end;
  554. end;
  555. function TMimeMess.AddPartTextEx(const Value: TStrings; const PartParent: TMimePart;
  556. PartCharset: TMimeChar; Raw: Boolean; PartEncoding: TMimeEncoding): TMimepart;
  557. begin
  558. Result := AddPart(PartParent);
  559. with Result do
  560. begin
  561. Value.SaveToStream(DecodedLines);
  562. Primary := 'text';
  563. Secondary := 'plain';
  564. Description := 'Message text';
  565. Disposition := 'inline';
  566. CharsetCode := PartCharset;
  567. EncodingCode := PartEncoding;
  568. ConvertCharset := not Raw;
  569. EncodePart;
  570. EncodePartHeader;
  571. end;
  572. end;
  573. function TMimeMess.AddPartHTML(const Value: TStrings; const PartParent: TMimePart): TMimepart;
  574. begin
  575. Result := AddPart(PartParent);
  576. with Result do
  577. begin
  578. Value.SaveToStream(DecodedLines);
  579. Primary := 'text';
  580. Secondary := 'html';
  581. Description := 'HTML text';
  582. Disposition := 'inline';
  583. CharsetCode := UTF_8;
  584. EncodingCode := ME_QUOTED_PRINTABLE;
  585. EncodePart;
  586. EncodePartHeader;
  587. end;
  588. end;
  589. function TMimeMess.AddPartTextFromFile(const FileName: String; const PartParent: TMimePart): TMimepart;
  590. var
  591. tmp: TStrings;
  592. begin
  593. tmp := TStringList.Create;
  594. try
  595. tmp.LoadFromFile(FileName);
  596. Result := AddPartText(tmp, PartParent);
  597. Finally
  598. tmp.Free;
  599. end;
  600. end;
  601. function TMimeMess.AddPartHTMLFromFile(const FileName: String; const PartParent: TMimePart): TMimepart;
  602. var
  603. tmp: TStrings;
  604. begin
  605. tmp := TStringList.Create;
  606. try
  607. tmp.LoadFromFile(FileName);
  608. Result := AddPartHTML(tmp, PartParent);
  609. Finally
  610. tmp.Free;
  611. end;
  612. end;
  613. function TMimeMess.AddPartBinary(const Stream: TStream; const FileName: string; const PartParent: TMimePart): TMimepart;
  614. begin
  615. Result := AddPart(PartParent);
  616. Result.DecodedLines.LoadFromStream(Stream);
  617. Result.MimeTypeFromExt(FileName);
  618. Result.Description := 'Attached file: ' + FileName;
  619. Result.Disposition := 'attachment';
  620. Result.FileName := FileName;
  621. Result.EncodingCode := ME_BASE64;
  622. Result.EncodePart;
  623. Result.EncodePartHeader;
  624. end;
  625. function TMimeMess.AddPartBinaryFromFile(const FileName: string; const PartParent: TMimePart): TMimepart;
  626. var
  627. tmp: TMemoryStream;
  628. begin
  629. tmp := TMemoryStream.Create;
  630. try
  631. tmp.LoadFromFile(FileName);
  632. Result := AddPartBinary(tmp, ExtractFileName(FileName), PartParent);
  633. finally
  634. tmp.Free;
  635. end;
  636. end;
  637. function TMimeMess.AddPartHTMLBinary(const Stream: TStream; const FileName, Cid: string; const PartParent: TMimePart): TMimepart;
  638. begin
  639. Result := AddPart(PartParent);
  640. Result.DecodedLines.LoadFromStream(Stream);
  641. Result.MimeTypeFromExt(FileName);
  642. Result.Description := 'Included file: ' + FileName;
  643. Result.Disposition := 'inline';
  644. Result.ContentID := Cid;
  645. Result.FileName := FileName;
  646. Result.EncodingCode := ME_BASE64;
  647. Result.EncodePart;
  648. Result.EncodePartHeader;
  649. end;
  650. function TMimeMess.AddPartHTMLBinaryFromFile(const FileName, Cid: string; const PartParent: TMimePart): TMimepart;
  651. var
  652. tmp: TMemoryStream;
  653. begin
  654. tmp := TMemoryStream.Create;
  655. try
  656. tmp.LoadFromFile(FileName);
  657. Result :=AddPartHTMLBinary(tmp, ExtractFileName(FileName), Cid, PartParent);
  658. finally
  659. tmp.Free;
  660. end;
  661. end;
  662. function TMimeMess.AddPartMess(const Value: TStrings; const PartParent: TMimePart): TMimepart;
  663. var
  664. part: Tmimepart;
  665. begin
  666. Result := AddPart(PartParent);
  667. part := AddPart(result);
  668. part.lines.addstrings(Value);
  669. part.DecomposeParts;
  670. with Result do
  671. begin
  672. Primary := 'message';
  673. Secondary := 'rfc822';
  674. Description := 'E-mail Message';
  675. EncodePart;
  676. EncodePartHeader;
  677. end;
  678. end;
  679. function TMimeMess.AddPartMessFromFile(const FileName: String; const PartParent: TMimePart): TMimepart;
  680. var
  681. tmp: TStrings;
  682. begin
  683. tmp := TStringList.Create;
  684. try
  685. tmp.LoadFromFile(FileName);
  686. Result := AddPartMess(tmp, PartParent);
  687. Finally
  688. tmp.Free;
  689. end;
  690. end;
  691. {==============================================================================}
  692. procedure TMimeMess.EncodeMessage;
  693. var
  694. l: TStringList;
  695. x: integer;
  696. begin
  697. //merge headers from THeaders and header field from MessagePart
  698. l := TStringList.Create;
  699. try
  700. FHeader.EncodeHeaders(l);
  701. x := IndexByBegin('CONTENT-TYPE', FMessagePart.Headers);
  702. if x >= 0 then
  703. l.add(FMessagePart.Headers[x]);
  704. x := IndexByBegin('CONTENT-DESCRIPTION', FMessagePart.Headers);
  705. if x >= 0 then
  706. l.add(FMessagePart.Headers[x]);
  707. x := IndexByBegin('CONTENT-DISPOSITION', FMessagePart.Headers);
  708. if x >= 0 then
  709. l.add(FMessagePart.Headers[x]);
  710. x := IndexByBegin('CONTENT-ID', FMessagePart.Headers);
  711. if x >= 0 then
  712. l.add(FMessagePart.Headers[x]);
  713. x := IndexByBegin('CONTENT-TRANSFER-ENCODING', FMessagePart.Headers);
  714. if x >= 0 then
  715. l.add(FMessagePart.Headers[x]);
  716. FMessagePart.Headers.Assign(l);
  717. finally
  718. l.Free;
  719. end;
  720. FMessagePart.ComposeParts;
  721. FLines.Assign(FMessagePart.Lines);
  722. end;
  723. {==============================================================================}
  724. procedure TMimeMess.DecodeMessage;
  725. begin
  726. FHeader.Clear;
  727. FHeader.DecodeHeaders(FLines);
  728. FMessagePart.Lines.Assign(FLines);
  729. FMessagePart.DecomposeParts;
  730. end;
  731. end.