Pop3cli

Форк
0
/
MimeMessage.cs 
433 строки · 15.6 Кб
1
#region License
2
//------------------------------------------------------------------------------
3
// Copyright (c) Dmitrii Evdokimov
4
// Source https://github.com/diev/
5
// 
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
// http://www.apache.org/licenses/LICENSE-2.0
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
//------------------------------------------------------------------------------
16

17
// based on an article https://www.codeproject.com/Articles/15611/POP3-Email-Client-with-full-MIME-Support-NET-2-0
18

19
// POP3 Email Client
20
// =================
21
//
22
// copyright by Peter Huber, Singapore, 2006
23
// this code is provided as is, bugs are probable, free for any use at own risk, no 
24
// responsibility accepted. All rights, title and interest in and to the accompanying content retained.  :-)
25
//
26
// based on Standard for ARPA Internet Text Messages, http://rfc.net/rfc822.html
27
// based on MIME Standard,  Internet Message Bodies, http://rfc.net/rfc2045.html
28
// based on MIME Standard, Media Types, http://rfc.net/rfc2046.html
29
#endregion
30

31
using System;
32
using System.Collections.Generic;
33
using System.IO;
34
using System.Net.Mail;
35
using System.Net.Mime;
36
using System.Text;
37

38
namespace Mime
39
{
40
    /// <summary>
41
    /// Stores all MIME decoded information of a received email. One email might consist of
42
    /// several MIME entities, which have a very similar structure to an email. A MimeMessage
43
    /// can be a top most level email or a MIME entity the emails contains.
44
    /// 
45
    /// According to various RFCs, MIME entities can contain other MIME entities 
46
    /// recursively. However, they usually need to be mapped to alternative views and 
47
    /// attachments, which are non recursive.
48
    ///
49
    /// MimeMessage inherits from System.Net.MailMessage, but provides additional receiving related information 
50
    /// </summary>
51
    public class MimeMessage : MailMessage
52
    {
53
        #region Constructors
54

55
        /// <summary>
56
        /// Default constructor
57
        /// </summary>
58
        public MimeMessage()
59
        {
60
            //for the moment, we assume to be at the top
61
            //should this entity become a child, TopParent will be overwritten
62
            TopParent = this;
63
            Entities = new List<MimeMessage>();
64
            UnknowHeaderlines = new List<string>();
65
        }
66

67
        #endregion Constructors
68

69
        #region Public properties
70

71
        /// <summary>
72
        /// To whom the email was delivered to
73
        /// </summary>
74
        public MailAddress DeliveredTo { get; set; }
75

76
        /// <summary>
77
        /// To whom the email was
78
        /// </summary>
79
        public MailAddress ReturnPath { get; set; }
80

81
        /// <summary>
82
        /// Date when the email was received
83
        /// </summary>
84
        public DateTime DeliveryDate { get; set; }
85

86
        /// <summary>
87
        /// ID @ server
88
        /// </summary>
89
        public string MessageId { get; set; }
90

91
        /// <summary>
92
        /// Probably '1.0'
93
        /// </summary>
94
        public string MimeVersion { get; set; }
95

96
        /// <summary>
97
        /// It may be desirable to allow one body to make reference to another. Accordingly, 
98
        /// bodies may be labelled using the "Content-ID" header field.    
99
        /// </summary>
100
        public string ContentId { get; set; }
101

102
        /// <summary>
103
        /// Some descriptive information for body
104
        /// </summary>
105
        public string ContentDescription { get; set; }
106

107
        /// <summary>
108
        /// ContentDisposition contains normally redundant information also stored in the 
109
        /// ContentType. Since ContentType is more detailed, it is enough to analyze ContentType
110
        /// 
111
        /// Something like:
112
        /// inline
113
        /// inline; filename="image001.gif
114
        /// attachment; filename="image001.jpg"
115
        /// </summary>
116
        public ContentDisposition ContentDisposition { get; set; }
117

118
        /// <summary>
119
        /// Something like "7bit" / "8bit" / "binary" / "quoted-printable" / "base64"
120
        /// </summary>
121
        public string TransferType { get; set; }
122

123
        /// <summary>
124
        /// Similar as TransferType, but .NET supports only "7bit" / "quoted-printable"
125
        /// / "base64" here, "bit8" is marked as "bit7" (i.e. no transfer encoding needed), 
126
        /// "binary" is illegal in SMTP
127
        /// </summary>
128
        public TransferEncoding ContentTransferEncoding { get; set; }
129

130
        /// <summary>
131
        /// The Content-Type field is used to specify the nature of the data in the body of a
132
        /// MIME entity, by giving media type and subtype identifiers, and by providing 
133
        /// auxiliary information that may be required for certain media types. Examples:
134
        /// text/plain;
135
        /// text/plain; charset=ISO-8859-1
136
        /// text/plain; charset=us-ascii
137
        /// text/plain; charset=utf-8
138
        /// text/html;
139
        /// text/html; charset=ISO-8859-1
140
        /// image/gif; name=image004.gif
141
        /// image/jpeg; name="image005.jpg"
142
        /// message/delivery-status
143
        /// message/rfc822
144
        /// multipart/alternative; boundary="----=_Part_4088_29304219.1115463798628"
145
        /// multipart/related; 	boundary="----=_Part_2067_9241611.1139322711488"
146
        /// multipart/mixed; 	boundary="----=_Part_3431_12384933.1139387792352"
147
        /// multipart/report; report-type=delivery-status; boundary="k04G6HJ9025016.1136391237/carbon.singnet.com.sg"
148
        /// application/pdf; name==?windows-1251?B?xODp5Obl8fIg7+7r/Ofu4uDy5ev88ero9SDq7uzo8uXy7uIgw/Dz7+/7?=
149
        /// </summary>
150
        public ContentType ContentType { get; set; }
151

152
        /// <summary>
153
        /// .NET framework combines MediaType (text) with subtype (plain) in one property, but
154
        /// often one or the other is needed alone. MediaMainType in this example would be 'text'.
155
        /// </summary>
156
        public string MediaMainType { get; set; }
157

158
        /// <summary>
159
        /// .NET framework combines MediaType (text) with subtype (plain) in one property, but
160
        /// often one or the other is needed alone. MediaSubType in this example would be 'plain'.
161
        /// </summary>
162
        public string MediaSubType { get; set; }
163

164
        /// <summary>
165
        /// MimeMessage can be used for any MIME entity, as a normal message body, an attachement or an alternative view. ContentStream
166
        /// provides the actual content of that MIME entity. It's mainly used internally and later mapped to the corresponding 
167
        /// .NET types.
168
        /// </summary>
169
        public Stream ContentStream { get; set; }
170

171
        /// <summary>
172
        /// A MIME entity can contain several MIME entities. A MIME entity has the same structure
173
        /// like an email. 
174
        /// </summary>
175
        public List<MimeMessage> Entities { get; set; }
176

177
        /// <summary>
178
        /// This entity might be part of a parent entity
179
        /// </summary>
180
        public MimeMessage Parent { get; set; }
181

182
        /// <summary>
183
        /// The top most MIME entity this MIME entity belongs to (grand grand grand .... parent)
184
        /// </summary>
185
        public MimeMessage TopParent { get; set; }
186

187
        /// <summary>
188
        /// Headerlines not interpretable by this class
189
        /// <example></example>
190
        /// </summary>
191
        public List<string> UnknowHeaderlines { get; set; } //
192

193
        /// <summary>
194
        /// Returns true if the message has attachments
195
        /// </summary>
196
        public bool HasAttachments => Attachments.Count > 0;
197

198
        #endregion Public properties
199

200
        #region Public methods
201

202
        /// <summary>
203
        /// Set all content type related fields
204
        /// </summary>
205
        public void SetContentTypeFields(string contentTypeString = null)
206
        {
207
            //set content type
208
            if (string.IsNullOrEmpty(contentTypeString))
209
            {
210
                ContentType = new ContentType()
211
                {
212
                    MediaType = MediaTypeNames.Text.Plain,
213
                    CharSet = "us-ascii"
214
                };
215
            }
216
            else
217
            {
218
                ContentType = new ContentType(contentTypeString.Trim()
219
                    .Replace(" = ", "="));
220
            }
221

222
            //set encoding (character set)
223
            if (ContentType.CharSet == null)
224
            {
225
                BodyEncoding = Encoding.ASCII;
226
            }
227
            else
228
            {
229
                BodyEncoding = Encoding.GetEncoding(ContentType.CharSet);
230
            }
231

232
            //set media main and sub type
233
            if (string.IsNullOrEmpty(ContentType.MediaType))
234
            {
235
                //no mediatype found
236
                ContentType.MediaType = MediaTypeNames.Text.Plain;
237
            }
238
            else
239
            {
240
                string mediaTypeString = ContentType.MediaType.Trim().ToLowerInvariant();
241
                int slashPosition = ContentType.MediaType.IndexOf("/");
242

243
                if (slashPosition < 1)
244
                {
245
                    //only main media type found
246
                    MediaMainType = mediaTypeString;
247
                    System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
248

249
                    if (MediaMainType == "text")
250
                    {
251
                        MediaSubType = "plain";
252
                    }
253
                    else
254
                    {
255
                        MediaSubType = "";
256
                    }
257
                }
258
                else
259
                {
260
                    //also submedia found
261
                    MediaMainType = mediaTypeString.Substring(0, slashPosition);
262

263
                    if (mediaTypeString.Length > slashPosition)
264
                    {
265
                        MediaSubType = mediaTypeString.Substring(slashPosition + 1);
266
                    }
267
                    else
268
                    {
269
                        if (MediaMainType == "text")
270
                        {
271
                            MediaSubType = "plain";
272
                        }
273
                        else
274
                        {
275
                            MediaSubType = "";
276
                            System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
277
                        }
278
                    }
279
                }
280
            }
281

282
            IsBodyHtml = MediaSubType.Equals("html");
283
        }
284

285
        /// <summary>
286
        /// Creates an empty child MIME entity from the parent MIME entity.
287
        /// 
288
        /// An email can consist of several MIME entities. A entity has the same structure
289
        /// like an email, that is header and body. The child inherits few properties 
290
        /// from the parent as default value.
291
        /// </summary>
292
        public MimeMessage CreateChildEntity()
293
        {
294
            MimeMessage child = new MimeMessage
295
            {
296
                Parent = this,
297
                TopParent = this.TopParent,
298
                ContentTransferEncoding = this.ContentTransferEncoding
299
            };
300

301
            return child;
302
        }
303

304
        /// <summary>
305
        /// Save this attachment to a file.
306
        /// </summary>
307
        /// <param name="attachment">Attachment to save.</param>
308
        /// <param name="path">Path to a file.</param>
309
        public void SaveAttachmentToFile(Attachment attachment, string path)
310
        {
311
            //byte[] allBytes = new byte[attachment.ContentStream.Length];
312
            //int bytesRead = attachment.ContentStream.Read(allBytes, 0, (int)attachment.ContentStream.Length);
313

314
            //string destinationFile = @"C:\" + attachment.Name;
315

316
            //BinaryWriter writer = new BinaryWriter(new FileStream(destinationFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None));
317
            //writer.Write(allBytes);
318
            //writer.Close();
319

320
            using (var file = File.OpenWrite(path))
321
            {
322
                attachment.ContentStream.CopyTo(file);
323
            }
324
        }
325

326
        /// <summary>
327
        /// Save all attachments to files in a folder.
328
        /// </summary>
329
        /// <param name="path">Path to a folder for files.</param>
330
        public void SaveAttachmentsToFolder(string path)
331
        {
332
            foreach (var attachment in Attachments)
333
            {
334
                SaveAttachmentToFile(attachment, Path.Combine(path, attachment.Name));
335
            }
336
        }
337

338
        #endregion Public methods
339

340
        #region Debug info
341

342
        private StringBuilder _mailStructure;
343

344
        private void AppendLine(string format, object arg)
345
        {
346
            if (arg != null)
347
            {
348
                string argString = arg.ToString();
349

350
                if (argString.Length > 0)
351
                {
352
                    _mailStructure.AppendLine(string.Format(format, argString));
353
                }
354
            }
355
        }
356

357
        private void DecodeEntity(MimeMessage entity)
358
        {
359
            AppendLine("From  : {0}", entity.From);
360
            AppendLine("Sender: {0}", entity.Sender);
361
            AppendLine("To    : {0}", entity.To);
362
            AppendLine("CC    : {0}", entity.CC);
363
            AppendLine("ReplyT: {0}", entity.ReplyToList);
364
            AppendLine("Subj  : {0}", entity.Subject);
365
            AppendLine("S-Enc : {0}", entity.SubjectEncoding);
366

367
            if (entity.DeliveryDate > DateTime.MinValue)
368
            {
369
                AppendLine("Date  : {0}", entity.DeliveryDate);
370
            }
371

372
            if (entity.Priority != MailPriority.Normal)
373
            {
374
                AppendLine("Priory: {0}", entity.Priority);
375
            }
376

377
            if (entity.Body.Length > 0)
378
            {
379
                AppendLine("Body  : {0} byte(s)", entity.Body.Length);
380
                AppendLine("B-Enc : {0}", entity.BodyEncoding);
381
            }
382
            else
383
            {
384
                if (entity.BodyEncoding != Encoding.ASCII)
385
                {
386
                    AppendLine("B-Enc : {0}", entity.BodyEncoding);
387
                }
388
            }
389

390
            AppendLine("T-Type: {0}", entity.TransferType);
391
            AppendLine("C-Type: {0}", entity.ContentType);
392
            AppendLine("C-Desc: {0}", entity.ContentDescription);
393
            AppendLine("C-Disp: {0}", entity.ContentDisposition);
394
            AppendLine("C-Id  : {0}", entity.ContentId);
395
            AppendLine("M-ID  : {0}", entity.MessageId);
396
            AppendLine("Mime  : Version {0}", entity.MimeVersion);
397

398
            if (entity.ContentStream != null)
399
            {
400
                AppendLine("Stream: Length {0}", entity.ContentStream.Length);
401
            }
402

403
            //decode all child MIME entities
404
            foreach (MimeMessage child in entity.Entities)
405
            {
406
                _mailStructure.AppendLine("------------------------------------");
407
                DecodeEntity(child);
408
            }
409

410
            if (entity.ContentType != null && 
411
                entity.ContentType.MediaType != null && 
412
                entity.ContentType.MediaType.StartsWith("multipart"))
413
            {
414
                AppendLine("End {0}", entity.ContentType.ToString());
415
            }
416
        }
417

418
        /// <summary>
419
        /// Convert structure of message into a string
420
        /// </summary>
421
        /// <returns>Debug text</returns>
422
        public string MailStructure()
423
        {
424
            _mailStructure = new StringBuilder(1000);
425
            DecodeEntity(this);
426
            _mailStructure.AppendLine("====================================");
427

428
            return _mailStructure.ToString();
429
        }
430

431
        #endregion Debug info
432
    }
433
}
434

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.