1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
|
\input texinfo.tex @c -*-texinfo-*-
@c %**start of header
@setfilename mu-scm.info
@settitle Mu-SCM User Manual
@c Use proper quote and backtick for code sections in PDF output
@c Cf. Texinfo manual 14.2
@set txicodequoteundirected
@set txicodequotebacktick
@documentencoding UTF-8
@c %**end of header
@include version.texi
@copying
Copyright @copyright{} 2025-@value{UPDATED-YEAR} Dirk-Jan C. Binnema
@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
copy of the license is included in the section entitled ``GNU Free
Documentation License.''
@end quotation
@end copying
@titlepage
@title Mu-SCM - extending @t{mu} with Guile Scheme
@subtitle version @value{VERSION}
@author Dirk-Jan C. Binnema
@c The following two commands start the copyright page.
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage
@dircategory The Algorithmic Language Scheme
@direntry
* Mu-SCM: (mu-scm). Guile support for the mu e-mail search engine
@end direntry
@contents
@ifnottex
@node Top
@top Mu-SCM Manual
@end ifnottex
@iftex
@node Welcome to @t{mu-scm}
@unnumbered Welcome to @t{mu-scm}
@end iftex
Welcome to @t{mu-scm}!
@t{mu} is a program for indexing and searching your e-mails. It can do so in
many different ways, but sometimes that may not be enough.
@t{mu-scm} is made for such cases. It embeds the Guile programming language into
@t{mu}. Guile is the @emph{GNU Ubiquitous Intelligent Language for Extensions} -
a version of the @emph{Scheme} programming language, the official GNU extension
language, and a member of the @emph{Lisp} family of programming languages --
like emacs-lisp, @emph{Racket}, Common Lisp.
@t{mu-scm} is replacing the older @t{mu-guile} bindings; some notable
differences are:
@itemize
@item No separate 'module', instead use mu itself:
This greatly reduces the number of 'moving parts' and mysterious errors for users
@item Automatically set up a reasonable environment:
@t{mu scm} simply reuses the user's @t{mu} configuration, simplifying setup
@item API improvements:
@t{mu-scm} has learned from @t{mu-guile} to make its APIs nicer to use
@item However, some parts are still missing:
@t{mu-scm} does not yet support all that @t{mu-guile} did. It's just getting
started.
@end itemize
If you're not familiar with Scheme or Lisp, @t{mu-scm} may be a fun way to learn
a bit more! Note: @t{mu-scm} is brand new and rather @strong{experimental} for
now, and APIs can still change without warning.
@menu
* Getting started::
* Shell::
* Scripts::
* API Reference with examples::
Appendices
* GNU Free Documentation License:: The license of this manual.
Indices
* Procedure Index::
* Variable Index::
@end menu
@node Getting started
@chapter Getting started
@menu
* Using distributions::
* Building it yourself::
* Starting the REPL::
* Listening on a Unix Domain Socket::
* Hooking up with GNU/Emacs and Geiser::
* Hooking up with Mu4e::
@end menu
This chapter walks you through the installation and basic setup.
@node Using distributions
@section Using distributions
At the time of writing, few distributions ship with an SCM-enabled @t{mu}, but
we know at least Guix@footnote{@url{https://guix.gnu.org/}}. For other
distributions, you need to build it yourself for now. Of course, this is fully
optional.
@node Building it yourself
@section Building it yourself
To build @t{mu} with SCM support, first you need to ensure you have installed
the required Guile development packages. The details of getting those vary
across environments / distributions, e.g.: on Fedora (as root):
@example
# dnf install guile30-devel
@end example
or on Debian/Ubuntu:
@example
$ sudo apt install guile-3.0-dev
@end example
With those packages in place, you can (re)build @t{mu} and @t{mu-scm} should be
built automatically if you did @emph{not} explicitly disable it.
Parts of @t{mu-scm} depend on @t{mu} being @emph{installed}, not just built;
however, you can still use it un-installed as well by setting an environment
variable @t{MU_SCM_DIR} to the source-directory, e.g.
@t{/home/user/sources/mu/scm}.
@node Starting the REPL
@section Starting the REPL
After installing @t{mu}, you can check the output of @command{mu info}. If
@t{mu-scm} is available, in the table you should find a line:
@example
| scm-support | yes | GNU Guile 3.x support (new)? |
@end example
You can then start an interactive shell, also known as the
``REPL''@footnote{Read-Eval-Print-Loop}.
@cindex REPL
@example
$ mu scm
[....]
Welcome to the mu shell!
GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@@(guile-user)>
@end example
Refer to the @xref{Shell} chapter to learn about the wonderful things you can do
in this shell.
@node Listening on a Unix Domain Socket
@section Listening on a Unix Domain Socket
Instead of using the interactive shell, it is also possible to expose the
REPL over a Unix domain socket, using the @t{--listen} flag.
@cindex Unix domain sockets
When you start @command{mu scm} with the @t{--listen} flag, it prints a
(randomized) UNIX domain socket name and blocks after that; for instance:
@example
$ mu scm --listen
/run/user/1000/mu-scm-15269.sock
@end example
You can connect to this with external tools, for instance with @command{socat}:
@example
$ socat - UNIX-CONNECT:/run/user/1000/mu-scm-15269.sock
GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This
program is free software, and you are welcome to redistribute it under certain
conditions; type `,show c' for details.
Enter `,help' for help.
scheme@@(guile-user)>
@end example
That is not much of improvement over the normal Guile shell, but you can of
course use more advanced tools; @xref{Hooking up with GNU/Emacs and Geiser}.
@node Hooking up with GNU/Emacs and Geiser
@section Hooking up with GNU/Emacs and Geiser
@cindex GNU/Emacs
@cindex Geiser
Many people like interacting with Guile through Emacs and the ``Geiser''
package, and that is possible with @command{mu scm} as well, using the Unix
domain socket, as discussed in @xref{Listening on a Unix Domain Socket}.
Assuming you have installed the @code{guile-geiser} package (available through
the ELPA package archive), the following snippet makes that easy:
@lisp
(require 'geiser-guile)
(defvar mu-scm-listen-command "mu scm --listen"
"mu command to start an scm repl listening on a socket.")
(defun mu-scm-geiser-connect ()
"Start a mu scm repl and connect to it using geiser.
Connect to mu's scm (guile) interface through Geiser."
(interactive)
(make-process
:name "*mu-scm-repl*"
:command `("sh" "-c" ,mu-scm-listen-command)
:filter (lambda (_proc chunk)
(when (string-match "^\\(mu-scm.*\\.sock\\)$" chunk)
(geiser-connect-local 'guile (match-string 1 chunk))))))
@end lisp
After evaluating this, you can use @command{M-x mu-scm-geiser-connect} to start
the REPL, with all the Geiser bells & whistles.
@node Hooking up with Mu4e
@section Hooking up with Mu4e
@cindex Mu4e
If you use @code{mu4e}, connecting to the SCM REPL is even easier than with
``plain'' Emacs.
First tell @code{mu4e} to starts it server with with @t{--listen} parameter:
@lisp
(setq mu4e-mu-scm-server t)
@end lisp
After that, (re)start @code{mu4e}.
Now should be able to connect to the REPL using @kbd{M-x mu4e-mu-scm-repl}. Like
@ref{Hooking up with GNU/Emacs and Geiser}, this depends on the
@code{geiser-guile} package.
The SCM instance uses the same database/store instance that @code{mu4e} uses.
@node Shell
@chapter Shell
This chapter discusses the @t{mu-scm}-powered shell.
After installation (@xref{Getting started}), you can start the @t{mu-scm} shell
by issuing:
@example
$ mu scm
@end example
This is the Guile
REPL@footnote{@url{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop}}
customized for @t{mu}. In particular, it supports all the common @t{mu}
command-line arguments for specifying where your @t{mu} stores its data and so
on (see the @t{mu} and @t{mu scm} man-pages for details).
@example
$ mu scm
[....]
Welcome to the mu shell!
GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@@(guile-user)>
@end example
This shell is set-up for use with @t{mu} with the module imported and the
message database loaded. So we can try some simple queries, using the
@code{mfind} function, which mimics @t{mu find}@footnote{It is called @t{mfind}
instead of @t{find} to avoid clashing with the core Guile function by that
name.}
@example
scheme@@(guile-user)> (mfind "rhinoceros")
$1 = (#<<message> 7f2aa671fce0>)
@end example
Which means we found one message matching @t{rhinoceros}. If you don't have such
a message, try some different query. We can then inspect the message, using the
@t{$1} temporary:
@example
scheme@@(guile-user)> (subject (car $1))
$2 = "Important message about African animals"
@end example
@node Scripts
@chapter Scripts
In the @ref{Shell} chapter, we saw how you can use @t{mu-scm} interactively. In
this also possible to run @emph{scripts}. Generally, you can invoke a script by
passing its name to @command{mu scm}, for example:
@example
mu scm path/to/script/myscript.scm
@end example
@t{mu-scm} expects scripts to have a procedure @code{main} of the form:
@deffn {Scheme Procedure} main script #:rest args
@end deffn
@t{main} receives the script (path) as its first argument, and any other
arguments in the list @t{args}.
Thus, an example script might look like:
@lisp
(use-modules (mu))
(define* (main script #:rest args)
(format #t "running script ~a and arguments ~s\n" script args)
(for-each
(lambda (msg)
(format #t "~a ~a\n"
(time->string (date msg))
(or (subject msg) "No subject")))
(mfind "hello AND date:2015.." #:max-results 5)))
@end lisp
You can run it like this:
@example
$ mu scm ~/myscript.scm some args 123
running script /home/user/myscript.scm and arguments ("some" "args" "123")
2015-01-02T12:41:13 Happy 2015! It's Day 2 - How Are Those Resolutions Coming?
2015-01-06T12:29:21 Brunch Sunday 11.1.
2015-01-06T18:05:27 Moderator's spam report for mu-discuss@@googlegroups.com
2015-01-13T11:37:27 Upvoted: The Story Behind the Users Who Make Reddit's Front Page
2015-01-16T17:06:23 [mu] combining maildirs in query (#559)
@end example
Quite likely, your output will differ from the above.
@node API Reference with examples
@chapter API Reference with examples
This chapter goes through the @t{mu-scm} API. For this, we need to understand a
few key concepts, represented in some GOOP objects and other data-structures:
@itemize
@item the @t{<store>} represents the mu database with information about messages
@item from the store, you can find @t{<message>} objects, each of which represent a specific message
(similar to what you get from @code{mu find})
@item the store also exposes tha contacts in the store as alists (``association lists'')
(similar to what you get from @code{mu cfind})
@end itemize
@menu
* Store:: where message information lives
* Message:: inspecting individual messages
* Miscellaneous:: other functions
* Helpers:: some helper functions
@end menu
@node Store
@section Store
The store represents the @t{mu} database, i.e., the place where @t{mu index}
stores information about messages and contacts.
While you could theoretically have @emph{multiple} stores, for now @t{mu-scm}
only supports a @emph{single} one, which is the store you opened when you
started @command{mu scm}.
For completeness and possible future use, store-related methods do take a
@t{store} parameter or a @t{#:store} keyword parameter, but it can be left out
for for now.
Hence, for brevity, in the API descriptions below, the @t{store} parameter is
implicit.
The store currently only exposes a few methods, described below.
@deffn {Scheme Procedure} mfind query [#:related? #f] [#:skip-dups? #f]
[#:sort-field 'date]
[#:reverse? #f] [#:max-results #f]
@end deffn
Perform a query for messages in the store, and return a list of message objects
(@xref{Message}) for the matches.
@itemize
@item @var{query} is a Mu query; see the @t{mu-query} man-page for details
@item @var{#:related?} whether @emph{related} messages should be included.
This is similar to the @t{--include-related} parameter for @command{mu find}
@item @var{#:skip-dups?} whether to exclude duplicate messages
This is similar to the @t{--skip-dups} parameter for @command{mu find}
@item @var{#:sort-field} a symbol, the message field to sort by
You can sort by the fields (see @command{mu info fields} that have a @t{value=yes})
@item @var{#:reverse?} whether to reverse the sort-direction (make it descending)
@item @var{#:max-results} the maximum number of results
By default @emph{all} matches are returned
@end itemize
@t{mfind} mimics the @command{mu find} command-line command.
Example usage:
@lisp
(mfind "capybara" #:skip-dups? #t #:sort-field 'subject)
=> (#<<message> 7f3c8ac09c00> #<<message> 7f3c8ac09be0>)
@end lisp
@deffn {Scheme Procedure} cfind pattern [#:personal? #f] [#:after #f] [#:max-results #f]
@end deffn
Search for contacts in the store, and return a list of contacts for the matches.
Each contact is an association list with at least a key (symbol @t{email}) with
e-mail address as its value, and possibly a @t{name} key with the contact's
name. In the future, other fields may be added.
@itemize
@item @var{pattern} is a basic case-insensitive PCRE-compatible regular expression
see the @t{pcre(3)} man-page for details
@item @var{#:personal?} if true, only match @emph{personal} contacts
A personal contact is a contact seen in message where ``you'' were an explicit
sender or recipient, thus excluding mailing-list. Personal addresses are those
that were specified at store creation time - see the @t{mu-init} man-page, in
particular the @t{--personal-address} parameter
@item @var{#:after} only include contacts last-seen after some time-point
Specified as the number of seconds since epoch. Helper-function
@code{iso-date->time-t} can be useful here.
@item @var{#:max-results} (optional) the maximum number of results
By default, @emph{all} matches are returned
@end itemize
@t{cfind} mimics the @command{mu cfind} command-line command.
Example usage:
@lisp
(car (cfind "smith" #:personal? #t))
=> ((name . "Hannibal Smith") (email . "jhs@@example.com"))
@end lisp
@deffn {Scheme Procedure} mcount
@end deffn
Return the number of messages in the store.
Example usage:
@lisp
(mcount)
=> 140728
@end lisp
@deffn {Scheme Procedure} store->alist
@end deffn
Retrieve an association list (``alist'') with information about the store.
Example:
@lisp
(store->alist)
=> ((batch-size . 50000) (created . 1741180008) (max-message-size . 100000000)
(personal-addresses "djcb@@example.com" "msx@@example.com")
(root-maildir . "/home/user/Maildir") (schema-version . 500))
@end lisp
More fields may be added.
@deffn {Scheme Procedure} root-maildir
@end deffn
Get the root maildir directory, that is, the root of under the directory under
which all messages reside.
This is equivalent to @code{(assoc-ref (store->alist) 'root-maildir)}.
@deffn {Scheme Procedure} personal-addresses
@end deffn
Get the list of personal-addresses as defined in the @code{mu} database, which
may be empty.
This is equivalent to @code{(or (assoc-ref (store->alist) 'personal-addresses) '())},
Any element in this list is either a plain e-mail address, or a PCRE-compatible
regular expression when the first and last characters are @t{/} (forward-slash);
see @t{pcre(3)} for further details.
@deffn {Scheme Procedure} labels
@end deffn
Get the list of all labels present in the store, which may be empty. Not to be
confused with @code{labels} procedure for a @code{message} object.
@deffn {Scheme Procedure} labels
@end deffn
Get the list of all labels present in the store, which may empty.
Not to be confused with @code{labels} procedure for a @code{message} object.
@node Message
@section Message
A @code{message} object represents the information about an e-mail message.
@t{mu} gets this information either from its database (the @t{mu} store), e.g.,
with @code{mfind} (see @xref{Store}) or by reading an email message from the
file-systems with @code{make-message}.
In many of the examples below we assume there is some @code{message} object,
e.g. as retrieved through:
@lisp
(define msg (car (mfind "hello")))
@end lisp
@anchor{full-message} Many of the procedures below use the internal
representation of the message from the database; this re-uses the same
information that @code{mu4e} uses:
@itemize
@item Basics: @code{subject}, @code{message-id}, @code{priority}
@item Contact fields: @code{from}, @code{to}, @code{cc}, @code{bcc}
@item Dates: @code{date} and @code{last-change}
@item ``Meta-data'' about a message: @code{maildir}, @code{path}, @code{size}, @code{labels}
@item Miscellaneous: @code{flags}, @code{references}, @code{thread-id}, @code{mailing-list}, @code{language}
@end itemize
However, that is not sufficient for all cases: @code{body} and @code{header}
need the full message. The same is true for @code{mime-parts}.
For these methods, @code{mu} needs to open the message file from the
file-system. This is handled transparently inside @t{mu-scm}, except that
full-method-procedures are a bit slower relatively to the database-only ones.
@subsection Basics
@deffn {Scheme Procedure} make-message path
@end deffn
Create a new message object from a file-system path.
This is a @emph{full message}, unlike the ones you get from a store-query (i.e.,
@code{mfind}).
@deffn {Scheme Procedure} subject message
@end deffn
Get the message subject, or @t{#f} if there is none.
For example:
@lisp
(subject msg)
=> "Hello!"
@end lisp
@deffn {Scheme Procedure} maildir message
@end deffn
Get the message subject, or @t{#f} if there is none.
For example:
@lisp
(maildir msg)
=> "/inbox"
@end lisp
@deffn {Scheme Procedure} path message
@end deffn
Get the file-system path for the message.
For example:
@lisp
(path msg)
=> "/home/user/Maildir/archive/cur/1546942532.adb906ab91921e10.hyperion:2,DS"
@end lisp
@deffn {Scheme Procedure} message-id message
@end deffn
Get the message's @t{Message-ID} field, or @t{#f} if there is none.
For example:
@lisp
(message-id msg)
=> "87a15477-dd66-43e5-a722-81c545d6af19@@gmail.com"
@end lisp
@deffn {Scheme Procedure} date message
@end deffn
Get the message's @t{Date} field (the sent-date), or @t{#f} if there is none.
@t{date} expressed the data as the number of seconds since epoch, @t{time_t}.
As a convenience, @t{iso-date} expresses the date as an ISO-8601-compatible
string or an empty string of the same length.
For example:
@lisp
(date msg)
=> 1750064431
(iso-date msg)
=> 2025-06-16T09:00:31
@end lisp
@deffn {Scheme Procedure} body message [#:html? #f]
@end deffn
Get the message body as a string, or return @code{#f} if not found.
If @var{#:html?} is non-@t{#f}, get the HTML-body instead.
This requires the @ref{full-message,,full message}.
@deffn {Scheme Procedure} message-id message
@end deffn
Get the message's @t{Message-ID} field, or @t{#f} if there is none.
For example:
@lisp
(message-id msg)
=> "87a15477-dd66-43e5-a722-81c545d6af19@@gmail.com"
@end lisp
@subsection MIME-parts
Messages consist of one or more MIME-parts, which include the body, attachments
and other parts. To get the MIME-parts for a message, you can use the
@code{mime-parts} method on a @code{message}.
@deffn {Scheme Procedure} mime-parts message
@end deffn
Get the MIME-parts for this message, as a list of @code{<mime-part>} objects.
A MIME-parts is an object with a few methods.
@deffn {Scheme Procedure} mime-part->alist mime-part
@end deffn
Get an association list (alist) describing the MIME part.
For example:
@lisp
;; describe the second MIME-part of the first message with an attachment
(mime-part->alist
(cadr (mime-parts
(car (mfind "flag:attach" #:max-results 1)))))
=> ((filename . "emacs.png") (size . 18188) (content-type . "image/png") (index . 1))
@end lisp
Depending on the MIME-part, different fields can be present:
@itemize
@item @t{index}
the index (number) of the part, 0-based
@item @t{mime-type}
the MIME-type of the part
@item @t{size}
the size of the part in bytes. For encoded parts, this is the @emph{encoded} size
@item @t{filename} the filename (for attachments).
This is as specified in the message, but with forward slashes and
control-characters removed or substituted with @t{-}.
@item @t{signed?}
is this part (cryptographically) signed?
@item @t{encrypted?}
is this part encrypted?
@end itemize
@deffn {Scheme Procedure} make-port mime-part [#:content-only? #f]
[#:decode? #t]
@end deffn
Get a read-port for the given MIME-part. Ports are the standard mechanism for
dealing with I/O in Guile; see its documentation for further details.
If @code{content-only?} is true, only include the contents, not headers. If
@code{decode?} is true, decode the content (from e.g., Base-64); in that
case, @code{content-only?} is implied to be #t.
@deffn {Scheme Procedure} write-to-file [#:filename #f] [#:overwrite? #f]
@end deffn
Write MIME-part to file.
Use @code{filename} is the file/path to use for writing; if this is @code{#f},
the name using the @code{filename} procedure.
If @code{overwrite?} is true, overwrite existing files of the same name;
otherwise, raise an error if the file already exists.
@deffn {Scheme Procedure} filename mime-part
@end deffn
Determine a filename for the given MIME-part.
This is either taken from the @t{filename} property of the MIME-part alist, or,
If that does not exist, a generic name.
@subsection Contacts
Message fields @t{To:}, @t{From:}, @t{Cc:} and @t{Bcc:} contain @emph{contacts}.
@t{mu-scm} represents those as list of contact-alists, or contacts for short.
Each contact is an alist with at least an @code{email} and optionally a
@code{name} field. For instance:
@lisp
(to msg)
=> (((name . "Hannibal Smith") (email . "jhs@@example.com"))
((email . "murdock@@example.com")))
@end lisp
@deffn {Scheme Procedure} from message
@end deffn
Get the list of message senders (usually a single one).
@deffn {Scheme Procedure} to message
@end deffn
Get the message's intended @t{To:} recipients list.
@deffn {Scheme Procedure} cc message
@end deffn
Get the message's intended carbon-copy @t{Cc:} recipients list.
@deffn {Scheme Procedure} bcc message
@end deffn
Get the message's intended blind carbon-copy @t{Bcc:} recipients list.
@subsection Flags
Message can have a number of properties or @emph{flags}.
@deffn {Scheme Procedure} flags message
@end deffn
Get the message's list of @emph{flags}. Flags are symbols, see @command{mu info
fields} for the list of all flags.
For example:
@lisp
(flags msg)
=> (draft seen personal)
@end lisp
There are some helpers to check for the presence of specific flags:
@deffn {Scheme Procedure} flag? message flag
@end deffn
Does the message have the given flag? @t{#t} or @t{#f}.
For example:
@lisp
(flags? msg 'personal)
=> #t
(flags? msg 'calendar)
=> #f
@end lisp
@deffn {Scheme Procedure} draft? message
@end deffn
Does the message have the @t{draft} flag? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} flagged? message
@end deffn
Does the message have the @t{flagged} flag? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} passed? message
@end deffn
Does the message have the @t{passed} flag? I.e., has it been forwarded?
Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} replied? message
@end deffn
Does the message have the @t{replied} flag? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} seen? message
@end deffn
Does the message have the @t{seen} flag? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} trashed? message
@end deffn
Does the message have the @t{trashed} flag? I.e., has it been marked for
removal? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} new? message
@end deffn
Is this a new message? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} signed? message
@end deffn
Is this a cryptographically signed message? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} encrypted? message
@end deffn
Is this an encrypted message? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} attach? message
@end deffn
Does the message have an attachment? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} unread? message
@end deffn
Is this message unread? I.e., either new or not seen? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} list? message
@end deffn
Is this a mailing-list message? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} personal? message
@end deffn
Is this a personal message? Returns @t{#t} or @t{#f}.
@deffn {Scheme Procedure} calendar? message
@end deffn
Does this message include a calendar invitation? Returns @t{#t} or @code{#f}.
@subsection Miscellaneous
@deffn {Scheme Procedure} changed message
@end deffn
Get the time of the message's last change (through @t{mu}), or @code{#f} if there
is none. The time is expressed the data as the number of seconds since epoch,
@t{time_t}.
For example:
@lisp
(last-change msg)
=> 1703336567
@end lisp
@deffn {Scheme Procedure} priority message
@end deffn
Get the message's priority. This is a symbol, either @t{high}, @t{normal} or
@t{low}, or @code{#f} if not present.
For example:
@lisp
(priority msg)
=> normal
@end lisp
@deffn {Scheme Procedure} size message
@end deffn
Get the message's size in bytes.
For example:
@lisp
(size msg)
=> 2815
@end lisp
@deffn {Scheme Procedure} labels message
@end deffn
Get the list of labels for this message. Not to be confused with the
@code{labels} procedure for a store.
For example:
@lisp
(labels msg)
=> ("foo" "bar")
@end lisp
@deffn {Scheme Procedure} language message
@end deffn
Get the ISO-639-1 language code for message's primary language or @code{#f} if not
found. This is available only if @t{mu} was built with CLD2 support, see
@command{mu info}. The language code is represented as a symbol, such as @t{en},
@t{nl} or @t{fi}.
For example:
@lisp
(language msg)
=> en
@end lisp
@deffn {Scheme Procedure} header message
@end deffn
Get some arbitrary, raw header from the message.
The @var{header} parameter is a case-insensitive string @emph{without} the colon
(@t{:}).
This requires the @ref{full-message,,full message}.
For example:
@lisp
(header msg "subject")
=> "Re: Musical chairs"
(header msg "From")
=> "\"Raul Endymion\" <raul@@example.com>"
(header msg "Something")
=> #f
@end lisp
@deffn {Scheme Procedure} references message
@end deffn
Get the list of references (message-ids of related messages) for this message.
This combines the @t{References} and @t{In-Reply-To} fields, from oldest to the
immediate parent. Returns @code{#f} if there are no references.
For example:
@lisp
(references msg)
=> ("439C1136.90504@@euler.org" "4399DD94.5070309@@euler.org"
"20051209233303.GA13812@@gauss.org" "439B41ED.2080402@@euler.org"
439A1E03.3090604@@euler.org" "20051211184308.GB13513@@gauss.org")
@end lisp
@deffn {Scheme Procedure} thread-id message
@end deffn
Get the oldest reference for the message or its message-id if there is none.
This is useful to identify the thread some message lives in.
For example:
@lisp
(thread-id msg)
=> "439C1136.90504@@euler.org"
@end lisp
For example:
@lisp
(references msg)
=> ("439C1136.90504@@euler.org" "4399DD94.5070309@@euler.org"
"20051209233303.GA13812@@gauss.org" "439B41ED.2080402@@euler.org"
439A1E03.3090604@@euler.org" "20051211184308.GB13513@@gauss.org")
@end lisp
@deffn {Scheme Procedure} mailing-list message
@end deffn
Get the mailing-list id for this message (corresponding with the @t{List-Id:}
field), or @code{#f} if there is none.
For example:
@lisp
(mailing-list msg)
=> "gnu-emacs-sources.gnu.org"
@end lisp
@c @deffn {Scheme Procedure} sexp message
@c @end deffn
@c Get the message's s-expression.
@c @t{mu} caches an s-expression for each message; this was designed as an
@c optimization for @code{mu4e}, but @t{mu-scm} uses it as well. The details of this
@c s-expression (a property-list) are internal to @t{mu} (so do not base your next
@c billion-dollar startup on it), but it can be useful for development and
@c debugging.
@node Miscellaneous
@section Miscellaneous
@defvar %options
@end defvar
An association-list (alist) of general options passed to @command{mu scm} or
their default values.
@lisp
%options
=> ((mu-home . #f) (quiet . #f) (debug . #f) (verbose . #f))
@end lisp
@c @defvar %preferences
@c @end defvar
@c An association list (alist) of user-preferences that influence interactive use.
@c E.g., the way how certain things are displayed. The alist maps symbols to values:
@c @itemize
@c @item @code{short-date}
@c a @code{strftime}-compatible string for the display format of short dates.
@c @item @code{utc?}
@c boolean, whether to assume UTC for dates/times, such as for @code{string->time} and @code{time->string}
@c @end itemize
@c @lisp
@c %preferences
@c ((short-date-format . "%F %T") (input-utc? . #f) (output-utc? . #f))
@c @end lisp
@node Helpers
@section Helpers
@deffn {Scheme Procedure} debug frm . args
@end deffn
@deffn {Scheme Procedure} info frm . args
@end deffn
@deffn {Scheme Procedure} warning frm . args
@end deffn
@deffn {Scheme Procedure} critical frm . args
@end deffn
Log using @t{mu}'s logging facilities at the given level (debug, info, warning
or critical). @code{frm} and @code{args} are expected to be a format string and
its arguments, respectively, according to Guile's @code{format} function.
Note: where the log output exactly appears (i.e., log-file, journal, console,
nowhere) dependis on the particulars of the system and how mu was started; see
the @t{mu (1)} man-page for details on the latter.
@deffn {Scheme Procedure} string->time timestr [#:utc? (assoc-ref %preferences 'utc?)]
@end deffn
Convert some ISO-8601-style time-string to a seconds-since-epoch @t{time_t}
value. @var{timestr} is expected to be in the @t{strftime}-format @t{%F%T}, or a
prefix thereof. Non-numerical characters are ignored.
You can influence whether UTC is assumed using the optional @code{#:utc?}
parameter. The input time/date format is fixed.
@c which uses @code{%preferences} for its default.
@deffn {Scheme Procedure} time->string
[#:format (assoc-ref %preferences 'short-date)]
[#:utc? (assoc-ref %preferences 'utc?)]
@end deffn
Convert a @t{time_t} value (``seconds-since-epoch'') to a string. The optional
@code{#:format} parameter (an @code{strftime}-compatible string) determines the
output format, while the @code{#:utc?} determines whether to use UTC.
@c Defaults are determined by the @code{%preferences} variable.
If @var{time_t} is @code{#f}, return @code{#f}.
@node GNU Free Documentation License
@appendix GNU Free Documentation License
@include fdl.texi
@page
@node Procedure Index
@unnumbered Procedure Index
This is an alphabetical list of all the public procedures and macros in @t{mu-scm}.
@printindex fn
@page
@node Variable Index
@unnumbered Variables Index
This is an alphabetical list of all the public variables @t{mu-scm}.
@printindex vr
@bye
|