• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

build/H03-May-2022-13,69312,892

docs/H03-May-2022-5,8565,262

examples/H03-May-2022-2,8502,155

gmime/H03-May-2022-58,83937,739

m4/H03-May-2022-10,1699,173

tests/H03-May-2022-22,46819,718

tools/H03-May-2022-896800

util/H03-May-2022-2,1991,625

AUTHORSH A D22-Feb-201734 21

COPYINGH A D22-Feb-201725.8 KiB505418

INSTALLH A D02-Sep-201815.4 KiB369287

Makefile.amH A D29-Oct-2018982 4328

Makefile.inH A D03-May-202230.8 KiB980874

NEWSH A D20-Mar-20206.5 KiB164112

PORTINGH A D26-Aug-201717.4 KiB404292

READMEH A D03-Mar-202031.4 KiB834626

README.mdH A D03-Mar-202031.4 KiB834626

TODOH A D28-Nov-20182.2 KiB6142

acinclude.m4H A D22-Feb-20175.2 KiB178166

aclocal.m4H A D20-Mar-202061.9 KiB1,7031,542

compileH A D11-Mar-20187.2 KiB349259

config.guessH A D11-Mar-201843.1 KiB1,4771,284

config.h.inH A D20-Mar-20204.7 KiB182123

config.subH A D11-Mar-201835.3 KiB1,8021,661

configureH A D20-Mar-2020640.1 KiB22,07518,523

configure.acH A D20-Mar-202019 KiB688599

depcompH A D11-Mar-201823 KiB792502

gmime.pc.inH A D03-May-2022342 1411

gmime.specH A D20-Mar-20201.9 KiB7858

gmime.spec.inH A D30-Mar-20171.9 KiB7860

gtk-doc.makeH A D15-Aug-201910.5 KiB322275

iconv-detect.cH A D16-Feb-20206.9 KiB224153

install-shH A D11-Mar-201815 KiB519337

ltmain.shH A D15-Feb-2015316.5 KiB11,1487,979

missingH A D11-Mar-20186.7 KiB216143

zentimer.hH A D15-Feb-20204.1 KiB190120

README

1# GMime
2
3[![Build Status](https://travis-ci.org/jstedfast/gmime.svg)](https://travis-ci.org/jstedfast/gmime)[![Coverity Scan Build Status](https://scan.coverity.com/projects/11948/badge.svg)](https://scan.coverity.com/projects/jstedfast-gmime)[![Coverage Status](https://coveralls.io/repos/github/jstedfast/gmime/badge.svg?branch=master)](https://coveralls.io/github/jstedfast/gmime?branch=master)
4
5## What is GMime?
6
7GMime is a C/C++ library which may be used for the creation and parsing of messages using the Multipurpose
8Internet Mail Extension (MIME) as defined by [numerous IETF specifications](https://github.com/jstedfast/gmime/blob/master/RFCs.md).
9
10GMime features an extremely robust high-performance parser designed to be able to preserve byte-for-byte information
11allowing developers to re-seralize the parsed messages back to a stream exactly as the parser found them. It also features
12integrated GnuPG and S/MIME v3.2 support.
13
14Built on top of GObject (the object system used by the [GNOME desktop](https://www.gnome.org)), many developers should find
15its API design and memory management very familiar.
16
17## History
18
19As a developer and user of Electronic Mail clients, I had come to
20realize that the vast majority of E-Mail client (and server) software
21had less-than-satisfactory MIME implementations. More often than not
22these E-Mail clients created broken MIME messages and/or would
23incorrectly try to parse a MIME message thus subtracting from the full
24benefits that MIME was meant to provide. GMime is meant to address
25this issue by following the MIME specification as closely as possible
26while also providing programmers with an extremely easy to use
27high-level application programming interface (API).
28
29## License Information
30
31The GMime library is Copyright (C) 2000-2020 Jeffrey Stedfast and is licensed under the LGPL v2.1
32
33    This library is free software; you can redistribute it and/or
34    modify it under the terms of the GNU Lesser General Public
35    License as published by the Free Software Foundation; either
36    version 2.1 of the License, or (at your option) any later version.
37
38    This library is distributed in the hope that it will be useful,
39    but WITHOUT ANY WARRANTY; without even the implied warranty of
40    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41    Lesser General Public License for more details.
42
43    You should have received a copy of the GNU Lesser General Public
44    License along with this library; if not, write to the Free Software
45    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
46
47
48## Getting the Source Code
49
50You can download official public release tarballs of GMime at
51[https://download.gnome.org/sources/gmime/](https://download.gnome.org/sources/gmime/)
52or
53[ftp://ftp.gnome.org/pub/GNOME/sources/gmime/](ftp://ftp.gnome.org/pub/GNOME/sources/gmime/).
54
55If you would like to contribute to the GMime project, it is recommended that you grab the
56source code from the official GitHub repository at
57[http://github.com/jstedfast/gmime](https://github.com/jstedfast/gmime). Cloning this repository
58can be done using the following command:
59
60    git clone https://github.com/jstedfast/gmime.git
61
62
63## Requirements
64
65For proper compilation and functionality of GMime, the following packages
66are REQUIRED:
67
68  - Glib version >= 2.32.0
69
70    Glib provides a number of portability-enhancing functions and types.
71    Glib is included in most GMime-supported operating system
72    distributions.  Glib sources may be obtained from:
73      ftp://ftp.gtk.org/pub/glib
74
75The following packages are RECOMMENDED:
76
77  - Libidn2 >= 2.0.0
78
79    Libidn2 provides APIs needed for encoding and decoding Internationalized
80    Domain Names. Libidn2 sources may be obtained from:
81      https://www.gnu.org/software/libidn/#downloading
82
83  - GPGME >= 1.8.0 (will build with 1.6.0, but will be missing some functionality)
84
85    GPGME (GnuPG Made Easy) provides high-level crypto APIs needed for
86    encryption, decryption, signing and signature verification for both
87    OpenPGP and S/MIME. GPGME sources may be obtained from:
88      https://www.gnupg.org/download/index.html#gpgme
89
90## Using GMime
91
92### Parsing Messages
93
94One of the more common operations that GMime is meant for is parsing email messages from arbitrary streams.
95To do this, you will need to use a `GMimeParser`:
96
97```c
98/* load a GMimeMessage from a stream */
99GMimeMessage *message;
100GMimeStream *stream;
101GMimeParser *parser;
102
103stream = g_mime_stream_file_open ("message.eml", "r", NULL);
104parser = g_mime_parser_new_with_stream (stream);
105
106/* Note: we can unref the stream now since the GMimeParser has a reference to it... */
107g_object_unref (stream);
108
109message = g_mime_parser_construct_message (parser);
110
111/* unref the parser since we no longer need it */
112g_object_unref (parser);
113```
114
115If you are planning to parse messages from an mbox stream, you can do something like this:
116
117```c
118GMimeMessage *message;
119GMimeStream *stream;
120GMimeParser *parser;
121gint64 offset;
122char *marker;
123
124stream = g_mime_stream_file_open ("Inbox.mbox", "r", NULL);
125parser = g_mime_parser_new_with_stream (stream);
126
127/* tell the parser to scan mbox-style "From " markers */
128g_mime_parser_set_scan_from (parser, TRUE);
129
130/* Note: we can unref the stream now since the GMimeParser has a reference to it... */
131g_object_unref (stream);
132
133while (!g_mime_parser_eos (parser)) {
134    /* load the next message from the mbox */
135    if ((message = g_mime_parser_construct_message (parser)) != NULL)
136        g_object_unref (message);
137
138    /* get information about the mbox "From " marker... */
139    offset = g_mime_parser_get_from_offset (parser);
140    marker = g_mime_parser_get_from (parser);
141}
142
143g_object_unref (parser);
144```
145
146### Getting the Body of a Message
147
148A common misunderstanding about email is that there is a well-defined message body and then a list
149of attachments. This is not really the case. The reality is that MIME is a tree structure of content,
150much like a file system.
151
152Luckily, MIME does define a set of general rules for how mail clients should interpret this tree
153structure of MIME parts. The `Content-Disposition` header is meant to provide hints to the receiving
154client as to which parts are meant to be displayed as part of the message body and which are meant
155to be interpreted as attachments.
156
157The `Content-Disposition` header will generally have one of two values: `inline` or `attachment`.
158
159The meaning of these value should be fairly obvious. If the value is `attachment`, then the content
160of said MIME part is meant to be presented as a file attachment separate from the core message.
161However, if the value is `inline`, then the content of that MIME part is meant to be displayed inline
162within the mail client's rendering of the core message body. If the `Content-Disposition` header does
163not exist, then it should be treated as if the value were `inline`.
164
165Technically, every part that lacks a `Content-Disposition` header or that is marked as `inline`, then,
166is part of the core message body.
167
168There's a bit more to it than that, though.
169
170Modern MIME messages will often contain a `multipart/alternative` MIME container which will generally contain
171a `text/plain` and `text/html` version of the text that the sender wrote. The `text/html` version is typically
172formatted much closer to what the sender saw in his or her WYSIWYG editor than the `text/plain` version.
173
174The reason for sending the message text in both formats is that not all mail clients are capable of displaying
175HTML.
176
177The receiving client should only display one of the alternative views contained within the `multipart/alternative`
178container. Since alternative views are listed in order of least faithful to most faithful with what the sender
179saw in his or her WYSIWYG editor, the receiving client *should* walk over the list of alternative views starting
180at the end and working backwards until it finds a part that it is capable of displaying.
181
182Example:
183```
184multipart/alternative
185  text/plain
186  text/html
187```
188
189As seen in the example above, the `text/html` part is listed last because it is the most faithful to
190what the sender saw in his or her WYSIWYG editor when writing the message.
191
192To make matters even more complicated, sometimes modern mail clients will use a `multipart/related`
193MIME container instead of a simple `text/html` part in order to embed images and other content
194within the HTML.
195
196Example:
197```
198multipart/alternative
199  text/plain
200  multipart/related
201    text/html
202    image/jpeg
203    video/mp4
204    image/png
205```
206
207In the example above, one of the alternative views is a `multipart/related` container which contains
208an HTML version of the message body that references the sibling video and images.
209
210Now that you have a rough idea of how a message is structured and how to interpret various MIME entities,
211the next step is learning how to traverse the MIME tree using GMime.
212
213### Traversing a GMimeMessage
214
215The top-level MIME entity of the message will generally either be a `GMimePart` or a `GMimeMultipart`.
216
217As an example, if you wanted to rip out all of the attachments of a message, your code might look
218something like this:
219
220```c
221GMimePartIter *iter = g_mime_part_iter_new (message);
222GPtrArray *attachments = g_ptr_array_new ();
223GPtrArray *multiparts = g_ptr_array_new ();
224
225/* collect our list of attachments and their parent multiparts */
226while (g_mime_part_iter_next (iter)) {
227    GMimeObject *current = g_mime_part_iter_get_current (iter);
228    GMimeObject *parent = g_mime_part_iter_get_parent (iter);
229
230    if (GMIME_IS_MULTIPART (parent) && GMIME_IS_PART (current)) {
231        GMimePart *part = (GMimePart *) current;
232
233        if (g_mime_part_is_attachment (part)) {
234            /* keep track of each attachment's parent multipart */
235            g_ptr_array_append (multiparts, parent);
236            g_ptr_array_append (attachments, part);
237        }
238    }
239}
240
241/* now remove each attachment from its parent multipart... */
242for (int i = 0; i < attachments->len; i++) {
243    GMimeMultipart *multipart = (GMimeMultipart *) multiparts->pdata[i];
244    GMimeObject *attachment = (GMimeObject *) attachments->pdata[i];
245
246    g_mime_multipart_remove (multipart, attachment);
247}
248```
249
250### Creating a Simple Message
251
252Creating MIME messages using GMime is really trivial.
253
254```csharp
255GMimeMessage *message;
256GMimePart *body;
257
258message = g_mime_message_new (TRUE);
259
260g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
261g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
262g_mime_message_set_subject (message, "How you doin?", NULL);
263
264body = g_mime_text_part_new_with_subtype ("plain");
265g_mime_text_part_set_text (body, "Hey Alice,\n\n"
266    "What are you up to this weekend? Monica is throwing one of her parties on\n"
267    "Saturday and I was hoping you could make it.\n\n"
268    "Will you be my +1?\n\n"
269    "-- Joey\n");
270
271g_mime_message_set_mime_part (message, (GMimeObject *) body);
272g_object_unref (body);
273```
274
275### Creating a Message with Attachments
276
277Attachments are just like any other `GMimePart`, the only difference is that they typically have
278a `Content-Disposition` header with a value of "attachment" instead of "inline" or no
279`Content-Disposition` header at all.
280
281Typically, when a mail client adds attachments to a message, it will create a `multipart/mixed`
282part and add the text body part and all of the file attachments to the `multipart/mixed`.
283
284Here's how you can do that with GMime:
285
286```c
287GMimeMultipart *multipart;
288GMimeDataWrapper *content;
289GMimeMessage *message;
290GMimePart *attachment;
291GMimeTextPart *body;
292GMimeStream *stream;
293
294message = g_mime_message_new (TRUE);
295g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
296g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
297g_mime_message_set_subject (message, "How you doin?", NULL);
298
299/* create our message text, just like before... */
300body = g_mime_text_part_new_with_subtype ("plain");
301g_mime_text_part_set_text (body, "Hey Alice,\n\n"
302    "What are you up to this weekend? Monica is throwing one of her parties on\n"
303    "Saturday and I was hoping you could make it.\n\n"
304    "Will you be my +1?\n\n"
305    "-- Joey\n");
306
307/* create an image attachment for the file located at path */
308attachment = g_mime_part_new_with_type ("image", "gif");
309g_mime_part_set_filename (attachment, basename (path));
310
311/* create the content for the image attachment */
312stream = g_mime_stream_fs_open (path, O_RDONLY, 0644, NULL);
313content = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_DEFAULT);
314g_object_unref (stream);
315
316/* set the content of the attachment */
317g_mime_part_set_content (attachment, content);
318g_object_unref (content);
319
320/* set the Content-Transfer-Encoding to base64 */
321g_mime_part_set_content_encoding (attachment, GMIME_CONTENT_ENCODING_BASE64);
322
323/* now create the multipart/mixed container to hold the message text and the image attachment */
324multipart = g_mime_multipart_new_with_subtype ("mixed");
325
326/* add the text body first */
327g_mime_multipart_add (multipart, (GMimeObject *) body);
328g_object_unref (body);
329
330/* now add the attachment(s) */
331g_mime_multipart_add (multipart, (GMimeObject *) attachment);
332g_object_unref (attachment);
333
334/* set the multipart/mixed as the message body */
335g_mime_message_set_mime_part (message, (GMimeObject *) multipart);
336g_object_unref (multipart);
337```
338
339Of course, that is just a simple example. A lot of modern mail clients such as Outlook or Thunderbird will
340send out both a `text/html` and a `text/plain` version of the message text. To do this, you'd create a
341`GMimeTextPart` for the `text/plain` part and another `GMimeTextPart` for the `text/html` part and then add
342them to a `multipart/alternative` like so:
343
344```c
345GMimeMultipart *mixed, *alternative;
346GMimeTextPart *plain, *html;
347GMimePart *attachment;
348
349/* see above for how to create each of these... */
350attachment = CreateAttachment ();
351plain = CreateTextPlainPart ();
352html = CreateTextHtmlPart ();
353
354/* Note: it is important that the text/html part is added second, because it is the
355 * most expressive version and (probably) the most faithful to the sender's WYSIWYG
356 * editor. */
357alternative = g_mime_multipart_with_subtype ("alternative");
358
359g_mime_multipart_add (alternative, (GMimeObject *) plain);
360g_object_unref (plain);
361
362g_mime_multipart_add (alternative, (GMimeObject *) html);
363g_object_unref (html);
364
365/* now create the multipart/mixed container to hold the multipart/alternative
366 * and the image attachment */
367mixed = g_mime_multipart_new_with_subtype ("mixed");
368
369g_mime_multipart_add (mixed, (GMimeObject *) alternative);
370g_object_unref (alternative);
371
372g_mime_multipart_add (mixed, (GMimeObject *) attachment);
373g_object_unref (attachment);
374
375/* now set the multipart/mixed as the message body */
376g_mime_message_set_mime_part (message, (GMimeObject *) mixed);
377g_object_unref (mixed);
378```
379
380### Encrypting Messages with S/MIME
381
382S/MIME uses an `application/pkcs7-mime` MIME part to encapsulate encrypted content (as well as other things).
383
384```c
385GMimeApplicationPkcs7Mime *encrypted;
386GMimeMessage *message;
387GError *err = NULL;
388GMimeObject *body;
389GPtrArray *rcpts;
390
391message = g_mime_message_new (TRUE);
392g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
393g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
394g_mime_message_set_subject (message, "How you doin?", NULL);
395
396/* create our message body (perhaps a multipart/mixed with the message text and some
397 * image attachments, for example) */
398body = CreateMessageBody ();
399
400/* create a list of key ids to encrypt to */
401rcpts = g_ptr_array_new ();
402g_ptr_array_add (rcpts, "alice@wonderland.com"); // or use her fingerprint
403
404/* now to encrypt our message body */
405if (!(encrypted = g_mime_application_pkcs7_mime_encrypt (body, GMIME_ENCRYPT_FLAGS_NONE, rcpts, &err))) {
406    fprintf (stderr, "encrypt failed: %s\n", err->message);
407    g_object_unref (body);
408    g_error_free (err);
409    return;
410}
411
412g_object_unref (body);
413
414g_mime_message_set_mime_part (message, encrypted);
415g_object_unref (encrypted);
416```
417
418### Decrypting S/MIME Messages
419
420As mentioned earlier, S/MIME uses an `application/pkcs7-mime` part with an "smime-type" parameter with a value of
421"enveloped-data" to encapsulate the encrypted content.
422
423The first thing you must do is find the `GMimeApplicationPkcs7Mime` part (see the section on traversing MIME parts).
424
425```c
426if (GMIME_IS_APPLICATION_PKCS7_MIME (entity)) {
427    GMimeApplicationPkcs7Mime *pkcs7 = (GMimeApplicationPkcs7Mime *) entity;
428    GMimeSecureMimeType smime_type;
429
430    smime_type = g_mime_application_pkcs7_mime_get_smime_type (pkcs7_mime);
431    if (smime_type == GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA)
432        return g_mime_application_pkcs7_mime_decrypt (pkcs7, 0, NULL, NULL, &err);
433}
434```
435
436### Encrypting Messages with PGP/MIME
437
438Unlike S/MIME, PGP/MIME uses `multipart/encrypted` to encapsulate its encrypted data.
439
440```c
441GMimeMultipartEncrypted *encrypted;
442GMimeCryptoContext *ctx;
443GMimeMessage *message;
444GError *err = NULL;
445GMimeObject *body;
446GPtrArray *rcpts;
447
448message = g_mime_message_new (TRUE);
449g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
450g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
451g_mime_message_set_subject (message, "How you doin?", NULL);
452
453/* create our message body (perhaps a multipart/mixed with the message text and some
454 * image attachments, for example) */
455body = CreateMessageBody ();
456
457/* create a list of key ids to encrypt to */
458rcpts = g_ptr_array_new ();
459g_ptr_array_add (rcpts, "alice@wonderland.com"); // or use her fingerprint
460
461/* now to encrypt our message body */
462ctx = g_mime_gpg_context_new ();
463
464encrypted = g_mime_multipart_encrypted_encrypt (ctx, body, FALSE, NULL, 0, 0, rcpts, &err);
465g_ptr_array_free (rcpts, TRUE);
466g_object_unref (body);
467g_object_unref (ctx);
468
469if (encrypted == NULL) {
470    fprintf (stderr, "encrypt failed: %s\n", err->message);
471    g_error_free (err);
472    return;
473}
474
475g_mime_message_set_mime_part (message, encrypted);
476g_object_unref (encrypted);
477```
478
479### Decrypting PGP/MIME Messages
480
481As mentioned earlier, PGP/MIME uses a `multipart/encrypted` part to encapsulate the encrypted content.
482
483A `multipart/encrypted` contains exactly 2 parts: the first `GMimeObject` is the version information while the
484second `GMimeObject` is the actual encrypted content and will typically be an `application/octet-stream`.
485
486The first thing you must do is find the `GMimeMultipartEncrypted` part (see the section on traversing MIME parts).
487
488```c
489if (GMIME_IS_MULTIPART_ENCRYPTED (entity)) {
490    GMimeMultipartEncrypted *encrypted = (GMimeMultipartEncrypted *) entity;
491
492    return g_mime_multipart_encrypted_decrypt (encrypted, 0, NULL, NULL, &err);
493}
494```
495
496### Digitally Signing Messages with S/MIME or PGP/MIME
497
498Both S/MIME and PGP/MIME use a `multipart/signed` to contain the signed content and the detached signature data.
499
500Here's how you might digitally sign a message using S/MIME:
501
502```c
503GMimeApplicationPkcs7Mime *pkcs7;
504GMimeMessage *message;
505GError *err = NULL;
506GMimeObject *body;
507
508message = g_mime_message_new (TRUE);
509g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
510g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
511g_mime_message_set_subject (message, "How you doin?", NULL);
512
513/* create our message body (perhaps a multipart/mixed with the message text and some
514 * image attachments, for example) */
515body = CreateMessageBody ();
516
517/* now to sign our message body */
518if (!(pkcs7 = g_mime_application_pkcs7_mime_sign (body, "joey@friends.com", GMIME_DIGEST_ALGO_DEFAULT, &err))) {
519    fprintf (stderr, "sign failed: %s\n", err->message);
520    g_object_unref (body);
521    g_error_free (err);
522    return;
523}
524
525g_object_unref (body);
526
527g_mime_message_set_mime_part (message, pkcs7);
528g_object_unref (pkcs7);
529```
530
531S/MIME also gives you the option of using a `multipart/signed` method of signing a message.
532
533```c
534GMimeMultipartSigned *ms;
535GMimeCryptoContext *ctx;
536GMimeMessage *message;
537GError *err = NULL;
538GMimeObject *body;
539
540message = g_mime_message_new (TRUE);
541g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
542g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
543g_mime_message_set_subject (message, "How you doin?", NULL);
544
545/* create our message body (perhaps a multipart/mixed with the message text and some
546 * image attachments, for example) */
547body = CreateMessageBody ();
548
549/* create our crypto context - needed because multipart/signed works for both S/MIME and PGP/MIME */
550ctx = g_mime_pkcs7_context_new ();
551
552/* now to sign our message body */
553if (!(ms = g_mime_multipart_signed_sign (ctx, body, "joey@friends.com", GMIME_DIGEST_ALGO_DEFAULT, &err))) {
554    fprintf (stderr, "sign failed: %s\n", err->message);
555    g_object_unref (body);
556    g_object_unref (ctx);
557    g_error_free (err);
558    return;
559}
560
561g_object_unref (body);
562g_object_unref (ctx);
563
564g_mime_message_set_mime_part (message, ms);
565g_object_unref (ms);
566```
567
568If you'd prefer to use PGP instead of S/MIME, things work almost exactly the same except that you
569would use the `GMimeGpgContext`.
570
571```c
572GMimeMultipartSigned *ms;
573GMimeCryptoContext *ctx;
574GMimeMessage *message;
575GError *err = NULL;
576GMimeObject *body;
577
578message = g_mime_message_new (TRUE);
579g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
580g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
581g_mime_message_set_subject (message, "How you doin?", NULL);
582
583/* create our message body (perhaps a multipart/mixed with the message text and some
584 * image attachments, for example) */
585body = CreateMessageBody ();
586
587/* create our crypto context - needed because multipart/signed works for both S/MIME and PGP/MIME */
588ctx = g_mime_gpg_context_new ();
589
590/* now to sign our message body */
591if (!(ms = g_mime_multipart_signed_sign (ctx, body, "joey@friends.com", GMIME_DIGEST_ALGO_DEFAULT, &err))) {
592    fprintf (stderr, "sign failed: %s\n", err->message);
593    g_object_unref (body);
594    g_object_unref (ctx);
595    g_error_free (err);
596    return;
597}
598
599g_object_unref (body);
600g_object_unref (ctx);
601
602g_mime_message_set_mime_part (message, ms);
603g_object_unref (ms);
604```
605
606### Verifying S/MIME and PGP/MIME Digital Signatures
607
608As mentioned earlier, both S/MIME and PGP/MIME typically use a `multipart/signed` part to contain the
609signed content and the detached signature data.
610
611A `multipart/signed` contains exactly 2 parts: the first `GMimeObject` is the signed content while the second
612`GMimeObject` is the detached signature and, by default, will either be a `GMimeApplicationPgpSignature` part
613or a `GMimeApplicationPkcs7Signature` part (depending on whether the sending client signed using OpenPGP or
614S/MIME).
615
616Because the `multipart/signed` part may have been signed by multiple signers, the
617`g_mime_multipart_signed_verify()` function returns a `GMimeSignatureList` which contains a list of
618digital signatures (one for each signer) that each contain their own metadata describing who that
619signer is and what the status of their signature is.
620
621```c
622if (GMIME_IS_MULTIPART_SIGNED (entity)) {
623    GMimeMultipartSigned *ms = (GMimeMultipartSigned *) entity;
624    GMimeSignatureList *signatures;
625    GError *err = NULL;
626    int i, count;
627
628    if (!(signatures = g_mime_multipart_signed_verify (ms, 0, &err))) {
629        fprintf (stderr, "verify failed: %s\n", err->message);
630        g_error_free (err);
631        return;
632    }
633
634    fputs ("\nSignatures:\n", stdout);
635    count = g_mime_signature_list_length (signatures);
636    for (i = 0; i < count; i++) {
637        GMimeSignature *sig = g_mime_signature_list_get_signature (signatures, i);
638        GMimeSignatureStatus status = g_mime_signature_get_status (sig);
639        GMimeCertificate *cert = g_mime_signature_get_certificate (sig);
640        time_t created = g_mime_signature_get_created (sig);
641        time_t expires = g_mime_signature_get_expires (sig);
642
643        fprintf (stdout, "\tName: %s\n", g_mime_certificate_get_name (cert));
644        fprintf (stdout, "\tKeyId: %s\n", g_mime_certificate_get_key_id (cert));
645        fprintf (stdout, "\tFingerprint: %s\n", g_mime_certificate_get_fingerprint (cert));
646
647        fprintf (stdout, "\tTrust: ");
648        switch (g_mime_certificate_get_trust (cert)) {
649        case GMIME_TRUST_UNKNOWN:   fputs ("Unknown\n", stdout); break;
650        case GMIME_TRUST_NEVER:     fputs ("Never\n", stdout); break;
651        case GMIME_TRUST_UNDEFINED: fputs ("Undefined\n", stdout); break;
652        case GMIME_TRUST_MARGINAL:  fputs ("Marginal\n", stdout); break;
653        case GMIME_TRUST_FULL:      fputs ("Full\n", stdout); break;
654        case GMIME_TRUST_ULTIMATE:  fputs ("Ultimate\n", stdout); break;
655        }
656
657        fprintf (stdout, "\tStatus: ");
658        if (status & GMIME_SIGNATURE_STATUS_RED)
659            fputs ("BAD\n", stdout);
660        else if (status & GMIME_SIGNATURE_STATUS_GREEN)
661            fputs ("GOOD\n", stdout);
662        else if (status & GMIME_SIGNATURE_STATUS_VALID)
663            fputs ("VALID\n", stdout);
664        else
665            fputs ("UNKNOWN\n", stdout);
666
667        fprintf (stdout, "\tSignature made on %s", ctime (&created));
668        if (expires != (time_t) 0)
669            fprintf (stdout, "\tSignature expires on %s", ctime (&expires));
670        else
671            fprintf (stdout, "\tSignature never expires\n");
672
673        fprintf (stdout, "\tErrors: ");
674        if (status & GMIME_SIGNATURE_STATUS_KEY_REVOKED)
675            fputs ("Key Revoked, ", stdout);
676        if (status & GMIME_SIGNATURE_STATUS_KEY_EXPIRED)
677            fputs ("Key Expired, ", stdout);
678        if (status & GMIME_SIGNATURE_STATUS_SIG_EXPIRED)
679            fputs ("Sig Expired, ", stdout);
680        if (status & GMIME_SIGNATURE_STATUS_KEY_MISSING)
681            fputs ("Key Missing, ", stdout);
682        if (status & GMIME_SIGNATURE_STATUS_CRL_MISSING)
683            fputs ("CRL Missing, ", stdout);
684        if (status & GMIME_SIGNATURE_STATUS_CRL_TOO_OLD)
685            fputs ("CRL Too Old, ", stdout);
686        if (status & GMIME_SIGNATURE_STATUS_BAD_POLICY)
687            fputs ("Bad Policy, ", stdout);
688        if (status & GMIME_SIGNATURE_STATUS_SYS_ERROR)
689            fputs ("System Error, ", stdout);
690        if (status & GMIME_SIGNATURE_STATUS_TOFU_CONFLICT)
691            fputs ("Tofu Conflict", stdout);
692        if ((status & GMIME_SIGNATURE_STATUS_ERROR_MASK) == 0)
693            fputs ("None", stdout);
694        fputs ("\n\n", stdout);
695    }
696
697    g_object_unref (signatures);
698}
699```
700
701It should be noted, however, that while most S/MIME clients will use the preferred `multipart/signed`
702approach, it is possible that you may encounter an `application/pkcs7-mime` part with an "smime-type"
703parameter set to "signed-data". Luckily, GMime can handle this format as well:
704
705```c
706if (GMIME_IS_APPLICATION_PKCS7_MIME (entity)) {
707    GMimeApplicationPkcs7Mime *pkcs7 = (GMimeApplicationPkcs7Mime *) entity;
708    GMimeSecureMimeType smime_type;
709
710    smime_type = g_mime_application_pkcs7_mime_get_smime_type (pkcs7);
711
712    if (smime_type == GMIME_SECURE_MIME_TYPE_SIGNED_DATA) {
713        /* extract the original content and get a list of signatures */
714        GMimeSignatureList *signatures;
715        GMimeObject extracted;
716        GError *err = NULL;
717        int i, count;
718
719        /* Note: if you are rendering the message, you'll want to render the
720         * extracted mime part rather than the application/pkcs7-mime part. */
721
722        if (!(signatures = g_mime_application_pkcs7_mime_verify (pkcs7, 0, &extracted, &err))) {
723            fprintf (stderr, "verify failed: %s\n", err->message);
724            g_error_free (err);
725            return;
726        }
727
728        count = g_mime_signature_list_length (signatures);
729        for (i = 0; i < count; i++) {
730            GMimeSignature *sig = g_mime_signature_list_get_signature (signatures, i);
731            /* ... */
732        }
733
734	g_object_unref (signatures);
735    }
736}
737```
738
739## Understanding Memory Management in GMime
740
741- Functions that return `const char *` return a pointer to a string stored on the `GObject` that will be released
742when the object itself is finalized and therefore should *never* be fed to `g_free()` by the caller.
743
744- Functions that return `char *` are left up to the caller to `g_free()` when the caller is done with them.
745
746### For functions throughout the GMime API that return an object reference:
747
748- If the function that returned the object allocated the object, then you need to unref it, otherwise you don't.
749
750For example, the `stream` in the following code would need to be unreffed (using `g_object_unref()`) because it was
751freshly allocated by the function:
752
753```c
754GMimeStream *stream = g_mime_stream_mem_new ();
755```
756
757The next example shows a function that returns a reference to an *existing* `GMimeStream` object that is stored on
758(and therefor managed by) the `GMimeDataWrapper` object:
759
760```c
761GMimeStream *stream = g_mime_data_wrapper_get_stream (wrapper);
762```
763
764In the above example, the `stream` *should not* be unreffed because the `stream` object's memory is managed by the
765`wrapper` object. In other words, when the `wrapper` object is freed, the `stream` will be freed as well.
766
767Where many developers get confused is when they create a new object and then add it to another object.
768
769For example:
770
771```c
772GMimeStream *stream = g_mime_stream_mem_new ();
773GMimeDataWrapper *wrapper = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_DEFAULT);
774g_object_unref (stream);
775```
776
777Even in this situation, it is necessary to unref the allocated object because all GMime functions that add an
778object to another object will ref that object themselves.
779
780In other words, in the above example, the `GMimeStream` is being added to the `GMimeDataWrapper`. The
781`GMimeDataWrapper` calls `g_object_ref()` on the `stream` which means that the `stream` object now has
782a ref count of 2.
783
784When `g_object_unref()` is called on the stream after adding it to the `GMimeDataWrapper`, the ref count drops
785down to 1.
786
787And when the `wrapper` object is eventually finalized after calling `g_object_unref()` on it, the ref count
788on the `stream` object will be reduced to 0 as well, thereby freeing the `stream` object.
789
790## Documentation
791
792This is the README file for GMime. Additional documentation related to
793development using GMime has been included within the source release
794of GMime.
795
796|               |Description                                                  |
797|---------------|-------------------------------------------------------------|
798|docs/reference/|Contains SGML and HTML versions of the GMime reference manual|
799|docs/tutorial/ |Contains SGML and HTML versions of the GMime tutorial|
800|AUTHORS        |List of primary authors (source code developers)|
801|COPYING        |The GNU Lesser General Public License, version 2|
802|INSTALL        |In-depth installation instructions|
803|TODO           |Description of planned GMime development|
804|PORTING        |Guide for developers porting their application from an older version of GMime|
805
806You can find online developer documentation at
807http://library.gnome.org/devel/gmime/stable/
808
809
810# Mailing Lists
811
812For discussion of GMime development (either of GMime itself or using
813GMime in your own application), you may find the GMime-Devel
814mailing-list helpful. To subscribe, please see
815[http://mail.gnome.org/mailman/listinfo/gmime-devel-list](http://mail.gnome.org/mailman/listinfo/gmime-devel-list)
816
817
818# Bindings
819
820Other developers have been working to make GMime available to programmers in other languages.
821The current list of known bindings are:
822
823|Language   |Location                                |
824|-----------|----------------------------------------|
825|Go         |https://github.com/sendgrid/go-gmime    |
826|Perl       |http://search.cpan.org/dist/MIME-Fast   |
827|C#         |https://github.com/jstedfast/MimeKit    |
828
829
830# Reporting Bugs
831
832Bugs may be reported to the GMime development team by creating a new
833[issue](https://github.com/jstedfast/gmime/issues).
834

README.md

1# GMime
2
3[![Build Status](https://travis-ci.org/jstedfast/gmime.svg)](https://travis-ci.org/jstedfast/gmime)[![Coverity Scan Build Status](https://scan.coverity.com/projects/11948/badge.svg)](https://scan.coverity.com/projects/jstedfast-gmime)[![Coverage Status](https://coveralls.io/repos/github/jstedfast/gmime/badge.svg?branch=master)](https://coveralls.io/github/jstedfast/gmime?branch=master)
4
5## What is GMime?
6
7GMime is a C/C++ library which may be used for the creation and parsing of messages using the Multipurpose
8Internet Mail Extension (MIME) as defined by [numerous IETF specifications](https://github.com/jstedfast/gmime/blob/master/RFCs.md).
9
10GMime features an extremely robust high-performance parser designed to be able to preserve byte-for-byte information
11allowing developers to re-seralize the parsed messages back to a stream exactly as the parser found them. It also features
12integrated GnuPG and S/MIME v3.2 support.
13
14Built on top of GObject (the object system used by the [GNOME desktop](https://www.gnome.org)), many developers should find
15its API design and memory management very familiar.
16
17## History
18
19As a developer and user of Electronic Mail clients, I had come to
20realize that the vast majority of E-Mail client (and server) software
21had less-than-satisfactory MIME implementations. More often than not
22these E-Mail clients created broken MIME messages and/or would
23incorrectly try to parse a MIME message thus subtracting from the full
24benefits that MIME was meant to provide. GMime is meant to address
25this issue by following the MIME specification as closely as possible
26while also providing programmers with an extremely easy to use
27high-level application programming interface (API).
28
29## License Information
30
31The GMime library is Copyright (C) 2000-2020 Jeffrey Stedfast and is licensed under the LGPL v2.1
32
33    This library is free software; you can redistribute it and/or
34    modify it under the terms of the GNU Lesser General Public
35    License as published by the Free Software Foundation; either
36    version 2.1 of the License, or (at your option) any later version.
37
38    This library is distributed in the hope that it will be useful,
39    but WITHOUT ANY WARRANTY; without even the implied warranty of
40    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41    Lesser General Public License for more details.
42
43    You should have received a copy of the GNU Lesser General Public
44    License along with this library; if not, write to the Free Software
45    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
46
47
48## Getting the Source Code
49
50You can download official public release tarballs of GMime at
51[https://download.gnome.org/sources/gmime/](https://download.gnome.org/sources/gmime/)
52or
53[ftp://ftp.gnome.org/pub/GNOME/sources/gmime/](ftp://ftp.gnome.org/pub/GNOME/sources/gmime/).
54
55If you would like to contribute to the GMime project, it is recommended that you grab the
56source code from the official GitHub repository at
57[http://github.com/jstedfast/gmime](https://github.com/jstedfast/gmime). Cloning this repository
58can be done using the following command:
59
60    git clone https://github.com/jstedfast/gmime.git
61
62
63## Requirements
64
65For proper compilation and functionality of GMime, the following packages
66are REQUIRED:
67
68  - Glib version >= 2.32.0
69
70    Glib provides a number of portability-enhancing functions and types.
71    Glib is included in most GMime-supported operating system
72    distributions.  Glib sources may be obtained from:
73      ftp://ftp.gtk.org/pub/glib
74
75The following packages are RECOMMENDED:
76
77  - Libidn2 >= 2.0.0
78
79    Libidn2 provides APIs needed for encoding and decoding Internationalized
80    Domain Names. Libidn2 sources may be obtained from:
81      https://www.gnu.org/software/libidn/#downloading
82
83  - GPGME >= 1.8.0 (will build with 1.6.0, but will be missing some functionality)
84
85    GPGME (GnuPG Made Easy) provides high-level crypto APIs needed for
86    encryption, decryption, signing and signature verification for both
87    OpenPGP and S/MIME. GPGME sources may be obtained from:
88      https://www.gnupg.org/download/index.html#gpgme
89
90## Using GMime
91
92### Parsing Messages
93
94One of the more common operations that GMime is meant for is parsing email messages from arbitrary streams.
95To do this, you will need to use a `GMimeParser`:
96
97```c
98/* load a GMimeMessage from a stream */
99GMimeMessage *message;
100GMimeStream *stream;
101GMimeParser *parser;
102
103stream = g_mime_stream_file_open ("message.eml", "r", NULL);
104parser = g_mime_parser_new_with_stream (stream);
105
106/* Note: we can unref the stream now since the GMimeParser has a reference to it... */
107g_object_unref (stream);
108
109message = g_mime_parser_construct_message (parser);
110
111/* unref the parser since we no longer need it */
112g_object_unref (parser);
113```
114
115If you are planning to parse messages from an mbox stream, you can do something like this:
116
117```c
118GMimeMessage *message;
119GMimeStream *stream;
120GMimeParser *parser;
121gint64 offset;
122char *marker;
123
124stream = g_mime_stream_file_open ("Inbox.mbox", "r", NULL);
125parser = g_mime_parser_new_with_stream (stream);
126
127/* tell the parser to scan mbox-style "From " markers */
128g_mime_parser_set_scan_from (parser, TRUE);
129
130/* Note: we can unref the stream now since the GMimeParser has a reference to it... */
131g_object_unref (stream);
132
133while (!g_mime_parser_eos (parser)) {
134    /* load the next message from the mbox */
135    if ((message = g_mime_parser_construct_message (parser)) != NULL)
136        g_object_unref (message);
137
138    /* get information about the mbox "From " marker... */
139    offset = g_mime_parser_get_from_offset (parser);
140    marker = g_mime_parser_get_from (parser);
141}
142
143g_object_unref (parser);
144```
145
146### Getting the Body of a Message
147
148A common misunderstanding about email is that there is a well-defined message body and then a list
149of attachments. This is not really the case. The reality is that MIME is a tree structure of content,
150much like a file system.
151
152Luckily, MIME does define a set of general rules for how mail clients should interpret this tree
153structure of MIME parts. The `Content-Disposition` header is meant to provide hints to the receiving
154client as to which parts are meant to be displayed as part of the message body and which are meant
155to be interpreted as attachments.
156
157The `Content-Disposition` header will generally have one of two values: `inline` or `attachment`.
158
159The meaning of these value should be fairly obvious. If the value is `attachment`, then the content
160of said MIME part is meant to be presented as a file attachment separate from the core message.
161However, if the value is `inline`, then the content of that MIME part is meant to be displayed inline
162within the mail client's rendering of the core message body. If the `Content-Disposition` header does
163not exist, then it should be treated as if the value were `inline`.
164
165Technically, every part that lacks a `Content-Disposition` header or that is marked as `inline`, then,
166is part of the core message body.
167
168There's a bit more to it than that, though.
169
170Modern MIME messages will often contain a `multipart/alternative` MIME container which will generally contain
171a `text/plain` and `text/html` version of the text that the sender wrote. The `text/html` version is typically
172formatted much closer to what the sender saw in his or her WYSIWYG editor than the `text/plain` version.
173
174The reason for sending the message text in both formats is that not all mail clients are capable of displaying
175HTML.
176
177The receiving client should only display one of the alternative views contained within the `multipart/alternative`
178container. Since alternative views are listed in order of least faithful to most faithful with what the sender
179saw in his or her WYSIWYG editor, the receiving client *should* walk over the list of alternative views starting
180at the end and working backwards until it finds a part that it is capable of displaying.
181
182Example:
183```
184multipart/alternative
185  text/plain
186  text/html
187```
188
189As seen in the example above, the `text/html` part is listed last because it is the most faithful to
190what the sender saw in his or her WYSIWYG editor when writing the message.
191
192To make matters even more complicated, sometimes modern mail clients will use a `multipart/related`
193MIME container instead of a simple `text/html` part in order to embed images and other content
194within the HTML.
195
196Example:
197```
198multipart/alternative
199  text/plain
200  multipart/related
201    text/html
202    image/jpeg
203    video/mp4
204    image/png
205```
206
207In the example above, one of the alternative views is a `multipart/related` container which contains
208an HTML version of the message body that references the sibling video and images.
209
210Now that you have a rough idea of how a message is structured and how to interpret various MIME entities,
211the next step is learning how to traverse the MIME tree using GMime.
212
213### Traversing a GMimeMessage
214
215The top-level MIME entity of the message will generally either be a `GMimePart` or a `GMimeMultipart`.
216
217As an example, if you wanted to rip out all of the attachments of a message, your code might look
218something like this:
219
220```c
221GMimePartIter *iter = g_mime_part_iter_new (message);
222GPtrArray *attachments = g_ptr_array_new ();
223GPtrArray *multiparts = g_ptr_array_new ();
224
225/* collect our list of attachments and their parent multiparts */
226while (g_mime_part_iter_next (iter)) {
227    GMimeObject *current = g_mime_part_iter_get_current (iter);
228    GMimeObject *parent = g_mime_part_iter_get_parent (iter);
229
230    if (GMIME_IS_MULTIPART (parent) && GMIME_IS_PART (current)) {
231        GMimePart *part = (GMimePart *) current;
232
233        if (g_mime_part_is_attachment (part)) {
234            /* keep track of each attachment's parent multipart */
235            g_ptr_array_append (multiparts, parent);
236            g_ptr_array_append (attachments, part);
237        }
238    }
239}
240
241/* now remove each attachment from its parent multipart... */
242for (int i = 0; i < attachments->len; i++) {
243    GMimeMultipart *multipart = (GMimeMultipart *) multiparts->pdata[i];
244    GMimeObject *attachment = (GMimeObject *) attachments->pdata[i];
245
246    g_mime_multipart_remove (multipart, attachment);
247}
248```
249
250### Creating a Simple Message
251
252Creating MIME messages using GMime is really trivial.
253
254```csharp
255GMimeMessage *message;
256GMimePart *body;
257
258message = g_mime_message_new (TRUE);
259
260g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
261g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
262g_mime_message_set_subject (message, "How you doin?", NULL);
263
264body = g_mime_text_part_new_with_subtype ("plain");
265g_mime_text_part_set_text (body, "Hey Alice,\n\n"
266    "What are you up to this weekend? Monica is throwing one of her parties on\n"
267    "Saturday and I was hoping you could make it.\n\n"
268    "Will you be my +1?\n\n"
269    "-- Joey\n");
270
271g_mime_message_set_mime_part (message, (GMimeObject *) body);
272g_object_unref (body);
273```
274
275### Creating a Message with Attachments
276
277Attachments are just like any other `GMimePart`, the only difference is that they typically have
278a `Content-Disposition` header with a value of "attachment" instead of "inline" or no
279`Content-Disposition` header at all.
280
281Typically, when a mail client adds attachments to a message, it will create a `multipart/mixed`
282part and add the text body part and all of the file attachments to the `multipart/mixed`.
283
284Here's how you can do that with GMime:
285
286```c
287GMimeMultipart *multipart;
288GMimeDataWrapper *content;
289GMimeMessage *message;
290GMimePart *attachment;
291GMimeTextPart *body;
292GMimeStream *stream;
293
294message = g_mime_message_new (TRUE);
295g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
296g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
297g_mime_message_set_subject (message, "How you doin?", NULL);
298
299/* create our message text, just like before... */
300body = g_mime_text_part_new_with_subtype ("plain");
301g_mime_text_part_set_text (body, "Hey Alice,\n\n"
302    "What are you up to this weekend? Monica is throwing one of her parties on\n"
303    "Saturday and I was hoping you could make it.\n\n"
304    "Will you be my +1?\n\n"
305    "-- Joey\n");
306
307/* create an image attachment for the file located at path */
308attachment = g_mime_part_new_with_type ("image", "gif");
309g_mime_part_set_filename (attachment, basename (path));
310
311/* create the content for the image attachment */
312stream = g_mime_stream_fs_open (path, O_RDONLY, 0644, NULL);
313content = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_DEFAULT);
314g_object_unref (stream);
315
316/* set the content of the attachment */
317g_mime_part_set_content (attachment, content);
318g_object_unref (content);
319
320/* set the Content-Transfer-Encoding to base64 */
321g_mime_part_set_content_encoding (attachment, GMIME_CONTENT_ENCODING_BASE64);
322
323/* now create the multipart/mixed container to hold the message text and the image attachment */
324multipart = g_mime_multipart_new_with_subtype ("mixed");
325
326/* add the text body first */
327g_mime_multipart_add (multipart, (GMimeObject *) body);
328g_object_unref (body);
329
330/* now add the attachment(s) */
331g_mime_multipart_add (multipart, (GMimeObject *) attachment);
332g_object_unref (attachment);
333
334/* set the multipart/mixed as the message body */
335g_mime_message_set_mime_part (message, (GMimeObject *) multipart);
336g_object_unref (multipart);
337```
338
339Of course, that is just a simple example. A lot of modern mail clients such as Outlook or Thunderbird will
340send out both a `text/html` and a `text/plain` version of the message text. To do this, you'd create a
341`GMimeTextPart` for the `text/plain` part and another `GMimeTextPart` for the `text/html` part and then add
342them to a `multipart/alternative` like so:
343
344```c
345GMimeMultipart *mixed, *alternative;
346GMimeTextPart *plain, *html;
347GMimePart *attachment;
348
349/* see above for how to create each of these... */
350attachment = CreateAttachment ();
351plain = CreateTextPlainPart ();
352html = CreateTextHtmlPart ();
353
354/* Note: it is important that the text/html part is added second, because it is the
355 * most expressive version and (probably) the most faithful to the sender's WYSIWYG
356 * editor. */
357alternative = g_mime_multipart_with_subtype ("alternative");
358
359g_mime_multipart_add (alternative, (GMimeObject *) plain);
360g_object_unref (plain);
361
362g_mime_multipart_add (alternative, (GMimeObject *) html);
363g_object_unref (html);
364
365/* now create the multipart/mixed container to hold the multipart/alternative
366 * and the image attachment */
367mixed = g_mime_multipart_new_with_subtype ("mixed");
368
369g_mime_multipart_add (mixed, (GMimeObject *) alternative);
370g_object_unref (alternative);
371
372g_mime_multipart_add (mixed, (GMimeObject *) attachment);
373g_object_unref (attachment);
374
375/* now set the multipart/mixed as the message body */
376g_mime_message_set_mime_part (message, (GMimeObject *) mixed);
377g_object_unref (mixed);
378```
379
380### Encrypting Messages with S/MIME
381
382S/MIME uses an `application/pkcs7-mime` MIME part to encapsulate encrypted content (as well as other things).
383
384```c
385GMimeApplicationPkcs7Mime *encrypted;
386GMimeMessage *message;
387GError *err = NULL;
388GMimeObject *body;
389GPtrArray *rcpts;
390
391message = g_mime_message_new (TRUE);
392g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
393g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
394g_mime_message_set_subject (message, "How you doin?", NULL);
395
396/* create our message body (perhaps a multipart/mixed with the message text and some
397 * image attachments, for example) */
398body = CreateMessageBody ();
399
400/* create a list of key ids to encrypt to */
401rcpts = g_ptr_array_new ();
402g_ptr_array_add (rcpts, "alice@wonderland.com"); // or use her fingerprint
403
404/* now to encrypt our message body */
405if (!(encrypted = g_mime_application_pkcs7_mime_encrypt (body, GMIME_ENCRYPT_FLAGS_NONE, rcpts, &err))) {
406    fprintf (stderr, "encrypt failed: %s\n", err->message);
407    g_object_unref (body);
408    g_error_free (err);
409    return;
410}
411
412g_object_unref (body);
413
414g_mime_message_set_mime_part (message, encrypted);
415g_object_unref (encrypted);
416```
417
418### Decrypting S/MIME Messages
419
420As mentioned earlier, S/MIME uses an `application/pkcs7-mime` part with an "smime-type" parameter with a value of
421"enveloped-data" to encapsulate the encrypted content.
422
423The first thing you must do is find the `GMimeApplicationPkcs7Mime` part (see the section on traversing MIME parts).
424
425```c
426if (GMIME_IS_APPLICATION_PKCS7_MIME (entity)) {
427    GMimeApplicationPkcs7Mime *pkcs7 = (GMimeApplicationPkcs7Mime *) entity;
428    GMimeSecureMimeType smime_type;
429
430    smime_type = g_mime_application_pkcs7_mime_get_smime_type (pkcs7_mime);
431    if (smime_type == GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA)
432        return g_mime_application_pkcs7_mime_decrypt (pkcs7, 0, NULL, NULL, &err);
433}
434```
435
436### Encrypting Messages with PGP/MIME
437
438Unlike S/MIME, PGP/MIME uses `multipart/encrypted` to encapsulate its encrypted data.
439
440```c
441GMimeMultipartEncrypted *encrypted;
442GMimeCryptoContext *ctx;
443GMimeMessage *message;
444GError *err = NULL;
445GMimeObject *body;
446GPtrArray *rcpts;
447
448message = g_mime_message_new (TRUE);
449g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
450g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
451g_mime_message_set_subject (message, "How you doin?", NULL);
452
453/* create our message body (perhaps a multipart/mixed with the message text and some
454 * image attachments, for example) */
455body = CreateMessageBody ();
456
457/* create a list of key ids to encrypt to */
458rcpts = g_ptr_array_new ();
459g_ptr_array_add (rcpts, "alice@wonderland.com"); // or use her fingerprint
460
461/* now to encrypt our message body */
462ctx = g_mime_gpg_context_new ();
463
464encrypted = g_mime_multipart_encrypted_encrypt (ctx, body, FALSE, NULL, 0, 0, rcpts, &err);
465g_ptr_array_free (rcpts, TRUE);
466g_object_unref (body);
467g_object_unref (ctx);
468
469if (encrypted == NULL) {
470    fprintf (stderr, "encrypt failed: %s\n", err->message);
471    g_error_free (err);
472    return;
473}
474
475g_mime_message_set_mime_part (message, encrypted);
476g_object_unref (encrypted);
477```
478
479### Decrypting PGP/MIME Messages
480
481As mentioned earlier, PGP/MIME uses a `multipart/encrypted` part to encapsulate the encrypted content.
482
483A `multipart/encrypted` contains exactly 2 parts: the first `GMimeObject` is the version information while the
484second `GMimeObject` is the actual encrypted content and will typically be an `application/octet-stream`.
485
486The first thing you must do is find the `GMimeMultipartEncrypted` part (see the section on traversing MIME parts).
487
488```c
489if (GMIME_IS_MULTIPART_ENCRYPTED (entity)) {
490    GMimeMultipartEncrypted *encrypted = (GMimeMultipartEncrypted *) entity;
491
492    return g_mime_multipart_encrypted_decrypt (encrypted, 0, NULL, NULL, &err);
493}
494```
495
496### Digitally Signing Messages with S/MIME or PGP/MIME
497
498Both S/MIME and PGP/MIME use a `multipart/signed` to contain the signed content and the detached signature data.
499
500Here's how you might digitally sign a message using S/MIME:
501
502```c
503GMimeApplicationPkcs7Mime *pkcs7;
504GMimeMessage *message;
505GError *err = NULL;
506GMimeObject *body;
507
508message = g_mime_message_new (TRUE);
509g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
510g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
511g_mime_message_set_subject (message, "How you doin?", NULL);
512
513/* create our message body (perhaps a multipart/mixed with the message text and some
514 * image attachments, for example) */
515body = CreateMessageBody ();
516
517/* now to sign our message body */
518if (!(pkcs7 = g_mime_application_pkcs7_mime_sign (body, "joey@friends.com", GMIME_DIGEST_ALGO_DEFAULT, &err))) {
519    fprintf (stderr, "sign failed: %s\n", err->message);
520    g_object_unref (body);
521    g_error_free (err);
522    return;
523}
524
525g_object_unref (body);
526
527g_mime_message_set_mime_part (message, pkcs7);
528g_object_unref (pkcs7);
529```
530
531S/MIME also gives you the option of using a `multipart/signed` method of signing a message.
532
533```c
534GMimeMultipartSigned *ms;
535GMimeCryptoContext *ctx;
536GMimeMessage *message;
537GError *err = NULL;
538GMimeObject *body;
539
540message = g_mime_message_new (TRUE);
541g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
542g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
543g_mime_message_set_subject (message, "How you doin?", NULL);
544
545/* create our message body (perhaps a multipart/mixed with the message text and some
546 * image attachments, for example) */
547body = CreateMessageBody ();
548
549/* create our crypto context - needed because multipart/signed works for both S/MIME and PGP/MIME */
550ctx = g_mime_pkcs7_context_new ();
551
552/* now to sign our message body */
553if (!(ms = g_mime_multipart_signed_sign (ctx, body, "joey@friends.com", GMIME_DIGEST_ALGO_DEFAULT, &err))) {
554    fprintf (stderr, "sign failed: %s\n", err->message);
555    g_object_unref (body);
556    g_object_unref (ctx);
557    g_error_free (err);
558    return;
559}
560
561g_object_unref (body);
562g_object_unref (ctx);
563
564g_mime_message_set_mime_part (message, ms);
565g_object_unref (ms);
566```
567
568If you'd prefer to use PGP instead of S/MIME, things work almost exactly the same except that you
569would use the `GMimeGpgContext`.
570
571```c
572GMimeMultipartSigned *ms;
573GMimeCryptoContext *ctx;
574GMimeMessage *message;
575GError *err = NULL;
576GMimeObject *body;
577
578message = g_mime_message_new (TRUE);
579g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey@friends.com");
580g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice@wonderland.com");
581g_mime_message_set_subject (message, "How you doin?", NULL);
582
583/* create our message body (perhaps a multipart/mixed with the message text and some
584 * image attachments, for example) */
585body = CreateMessageBody ();
586
587/* create our crypto context - needed because multipart/signed works for both S/MIME and PGP/MIME */
588ctx = g_mime_gpg_context_new ();
589
590/* now to sign our message body */
591if (!(ms = g_mime_multipart_signed_sign (ctx, body, "joey@friends.com", GMIME_DIGEST_ALGO_DEFAULT, &err))) {
592    fprintf (stderr, "sign failed: %s\n", err->message);
593    g_object_unref (body);
594    g_object_unref (ctx);
595    g_error_free (err);
596    return;
597}
598
599g_object_unref (body);
600g_object_unref (ctx);
601
602g_mime_message_set_mime_part (message, ms);
603g_object_unref (ms);
604```
605
606### Verifying S/MIME and PGP/MIME Digital Signatures
607
608As mentioned earlier, both S/MIME and PGP/MIME typically use a `multipart/signed` part to contain the
609signed content and the detached signature data.
610
611A `multipart/signed` contains exactly 2 parts: the first `GMimeObject` is the signed content while the second
612`GMimeObject` is the detached signature and, by default, will either be a `GMimeApplicationPgpSignature` part
613or a `GMimeApplicationPkcs7Signature` part (depending on whether the sending client signed using OpenPGP or
614S/MIME).
615
616Because the `multipart/signed` part may have been signed by multiple signers, the
617`g_mime_multipart_signed_verify()` function returns a `GMimeSignatureList` which contains a list of
618digital signatures (one for each signer) that each contain their own metadata describing who that
619signer is and what the status of their signature is.
620
621```c
622if (GMIME_IS_MULTIPART_SIGNED (entity)) {
623    GMimeMultipartSigned *ms = (GMimeMultipartSigned *) entity;
624    GMimeSignatureList *signatures;
625    GError *err = NULL;
626    int i, count;
627
628    if (!(signatures = g_mime_multipart_signed_verify (ms, 0, &err))) {
629        fprintf (stderr, "verify failed: %s\n", err->message);
630        g_error_free (err);
631        return;
632    }
633
634    fputs ("\nSignatures:\n", stdout);
635    count = g_mime_signature_list_length (signatures);
636    for (i = 0; i < count; i++) {
637        GMimeSignature *sig = g_mime_signature_list_get_signature (signatures, i);
638        GMimeSignatureStatus status = g_mime_signature_get_status (sig);
639        GMimeCertificate *cert = g_mime_signature_get_certificate (sig);
640        time_t created = g_mime_signature_get_created (sig);
641        time_t expires = g_mime_signature_get_expires (sig);
642
643        fprintf (stdout, "\tName: %s\n", g_mime_certificate_get_name (cert));
644        fprintf (stdout, "\tKeyId: %s\n", g_mime_certificate_get_key_id (cert));
645        fprintf (stdout, "\tFingerprint: %s\n", g_mime_certificate_get_fingerprint (cert));
646
647        fprintf (stdout, "\tTrust: ");
648        switch (g_mime_certificate_get_trust (cert)) {
649        case GMIME_TRUST_UNKNOWN:   fputs ("Unknown\n", stdout); break;
650        case GMIME_TRUST_NEVER:     fputs ("Never\n", stdout); break;
651        case GMIME_TRUST_UNDEFINED: fputs ("Undefined\n", stdout); break;
652        case GMIME_TRUST_MARGINAL:  fputs ("Marginal\n", stdout); break;
653        case GMIME_TRUST_FULL:      fputs ("Full\n", stdout); break;
654        case GMIME_TRUST_ULTIMATE:  fputs ("Ultimate\n", stdout); break;
655        }
656
657        fprintf (stdout, "\tStatus: ");
658        if (status & GMIME_SIGNATURE_STATUS_RED)
659            fputs ("BAD\n", stdout);
660        else if (status & GMIME_SIGNATURE_STATUS_GREEN)
661            fputs ("GOOD\n", stdout);
662        else if (status & GMIME_SIGNATURE_STATUS_VALID)
663            fputs ("VALID\n", stdout);
664        else
665            fputs ("UNKNOWN\n", stdout);
666
667        fprintf (stdout, "\tSignature made on %s", ctime (&created));
668        if (expires != (time_t) 0)
669            fprintf (stdout, "\tSignature expires on %s", ctime (&expires));
670        else
671            fprintf (stdout, "\tSignature never expires\n");
672
673        fprintf (stdout, "\tErrors: ");
674        if (status & GMIME_SIGNATURE_STATUS_KEY_REVOKED)
675            fputs ("Key Revoked, ", stdout);
676        if (status & GMIME_SIGNATURE_STATUS_KEY_EXPIRED)
677            fputs ("Key Expired, ", stdout);
678        if (status & GMIME_SIGNATURE_STATUS_SIG_EXPIRED)
679            fputs ("Sig Expired, ", stdout);
680        if (status & GMIME_SIGNATURE_STATUS_KEY_MISSING)
681            fputs ("Key Missing, ", stdout);
682        if (status & GMIME_SIGNATURE_STATUS_CRL_MISSING)
683            fputs ("CRL Missing, ", stdout);
684        if (status & GMIME_SIGNATURE_STATUS_CRL_TOO_OLD)
685            fputs ("CRL Too Old, ", stdout);
686        if (status & GMIME_SIGNATURE_STATUS_BAD_POLICY)
687            fputs ("Bad Policy, ", stdout);
688        if (status & GMIME_SIGNATURE_STATUS_SYS_ERROR)
689            fputs ("System Error, ", stdout);
690        if (status & GMIME_SIGNATURE_STATUS_TOFU_CONFLICT)
691            fputs ("Tofu Conflict", stdout);
692        if ((status & GMIME_SIGNATURE_STATUS_ERROR_MASK) == 0)
693            fputs ("None", stdout);
694        fputs ("\n\n", stdout);
695    }
696
697    g_object_unref (signatures);
698}
699```
700
701It should be noted, however, that while most S/MIME clients will use the preferred `multipart/signed`
702approach, it is possible that you may encounter an `application/pkcs7-mime` part with an "smime-type"
703parameter set to "signed-data". Luckily, GMime can handle this format as well:
704
705```c
706if (GMIME_IS_APPLICATION_PKCS7_MIME (entity)) {
707    GMimeApplicationPkcs7Mime *pkcs7 = (GMimeApplicationPkcs7Mime *) entity;
708    GMimeSecureMimeType smime_type;
709
710    smime_type = g_mime_application_pkcs7_mime_get_smime_type (pkcs7);
711
712    if (smime_type == GMIME_SECURE_MIME_TYPE_SIGNED_DATA) {
713        /* extract the original content and get a list of signatures */
714        GMimeSignatureList *signatures;
715        GMimeObject extracted;
716        GError *err = NULL;
717        int i, count;
718
719        /* Note: if you are rendering the message, you'll want to render the
720         * extracted mime part rather than the application/pkcs7-mime part. */
721
722        if (!(signatures = g_mime_application_pkcs7_mime_verify (pkcs7, 0, &extracted, &err))) {
723            fprintf (stderr, "verify failed: %s\n", err->message);
724            g_error_free (err);
725            return;
726        }
727
728        count = g_mime_signature_list_length (signatures);
729        for (i = 0; i < count; i++) {
730            GMimeSignature *sig = g_mime_signature_list_get_signature (signatures, i);
731            /* ... */
732        }
733
734	g_object_unref (signatures);
735    }
736}
737```
738
739## Understanding Memory Management in GMime
740
741- Functions that return `const char *` return a pointer to a string stored on the `GObject` that will be released
742when the object itself is finalized and therefore should *never* be fed to `g_free()` by the caller.
743
744- Functions that return `char *` are left up to the caller to `g_free()` when the caller is done with them.
745
746### For functions throughout the GMime API that return an object reference:
747
748- If the function that returned the object allocated the object, then you need to unref it, otherwise you don't.
749
750For example, the `stream` in the following code would need to be unreffed (using `g_object_unref()`) because it was
751freshly allocated by the function:
752
753```c
754GMimeStream *stream = g_mime_stream_mem_new ();
755```
756
757The next example shows a function that returns a reference to an *existing* `GMimeStream` object that is stored on
758(and therefor managed by) the `GMimeDataWrapper` object:
759
760```c
761GMimeStream *stream = g_mime_data_wrapper_get_stream (wrapper);
762```
763
764In the above example, the `stream` *should not* be unreffed because the `stream` object's memory is managed by the
765`wrapper` object. In other words, when the `wrapper` object is freed, the `stream` will be freed as well.
766
767Where many developers get confused is when they create a new object and then add it to another object.
768
769For example:
770
771```c
772GMimeStream *stream = g_mime_stream_mem_new ();
773GMimeDataWrapper *wrapper = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_DEFAULT);
774g_object_unref (stream);
775```
776
777Even in this situation, it is necessary to unref the allocated object because all GMime functions that add an
778object to another object will ref that object themselves.
779
780In other words, in the above example, the `GMimeStream` is being added to the `GMimeDataWrapper`. The
781`GMimeDataWrapper` calls `g_object_ref()` on the `stream` which means that the `stream` object now has
782a ref count of 2.
783
784When `g_object_unref()` is called on the stream after adding it to the `GMimeDataWrapper`, the ref count drops
785down to 1.
786
787And when the `wrapper` object is eventually finalized after calling `g_object_unref()` on it, the ref count
788on the `stream` object will be reduced to 0 as well, thereby freeing the `stream` object.
789
790## Documentation
791
792This is the README file for GMime. Additional documentation related to
793development using GMime has been included within the source release
794of GMime.
795
796|               |Description                                                  |
797|---------------|-------------------------------------------------------------|
798|docs/reference/|Contains SGML and HTML versions of the GMime reference manual|
799|docs/tutorial/ |Contains SGML and HTML versions of the GMime tutorial|
800|AUTHORS        |List of primary authors (source code developers)|
801|COPYING        |The GNU Lesser General Public License, version 2|
802|INSTALL        |In-depth installation instructions|
803|TODO           |Description of planned GMime development|
804|PORTING        |Guide for developers porting their application from an older version of GMime|
805
806You can find online developer documentation at
807http://library.gnome.org/devel/gmime/stable/
808
809
810# Mailing Lists
811
812For discussion of GMime development (either of GMime itself or using
813GMime in your own application), you may find the GMime-Devel
814mailing-list helpful. To subscribe, please see
815[http://mail.gnome.org/mailman/listinfo/gmime-devel-list](http://mail.gnome.org/mailman/listinfo/gmime-devel-list)
816
817
818# Bindings
819
820Other developers have been working to make GMime available to programmers in other languages.
821The current list of known bindings are:
822
823|Language   |Location                                |
824|-----------|----------------------------------------|
825|Go         |https://github.com/sendgrid/go-gmime    |
826|Perl       |http://search.cpan.org/dist/MIME-Fast   |
827|C#         |https://github.com/jstedfast/MimeKit    |
828
829
830# Reporting Bugs
831
832Bugs may be reported to the GMime development team by creating a new
833[issue](https://github.com/jstedfast/gmime/issues).
834