aerc: recover: recover emails from tempdir after a crash v1 APPLIED

Koni Marti: 1
 recover: recover emails from tempdir after a crash

 1 files changed, 110 insertions(+), 0 deletions(-)
#683142 alpine-edge.yml success
#683143 debian-stable.yml success
#683144 fedora-latest.yml success
#683145 openbsd.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~rjarry/aerc-devel/patches/28824/mbox | git am -3
Learn more about email & git

[PATCH aerc] recover: recover emails from tempdir after a crash Export this patch

implements a recover command that searches the local temp dir for aerc
emails. If a file is found and selected, a new composer tab will open
with the file contents as the message body. No header data is stored in
the temp file and thus this information cannot be recovered.
Recover will not remove the temporary file unless the force flag (-f) is
explicitly used.

This recovery method only works when the editor buffer is saved to
disk and the Close() function of the composer has not been called yet.

Sending, postponing or quitting will call the Close() function which
removes the temporary file completely. After Close() is called, no
recovery is possible anymore.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
If there are no recoverable files for testing, you can compose a new
message and save the file buffer. Run 'killall aerc' to simulate a crash
and at the next start, you should be able to recover the message.
As a reminder, we should perform a code review of the send and postpone
commands to make sure they do not close the composer unless the message
has been properly saved or sent.
 commands/account/recover.go | 110 ++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 commands/account/recover.go

diff --git a/commands/account/recover.go b/commands/account/recover.go
new file mode 100644
index 0000000..a167d50
--- /dev/null
+++ b/commands/account/recover.go
@@ -0,0 +1,110 @@
package account

import (


type Recover struct{}

func init() {

func (Recover) Aliases() []string {
	return []string{"recover"}

func (Recover) Complete(aerc *widgets.Aerc, args []string) []string {
	// file name of temp file is hard-coded in the NewComposer() function
	files, err := filepath.Glob(
		filepath.Join(os.TempDir(), "aerc-compose-*.eml"),
	if err != nil {
		return []string{}
	arg := strings.Join(args, " ")
	if arg != "" {
		for i, file := range files {
			files[i] = strings.Join([]string{arg, file}, " ")
	return files

func (Recover) Execute(aerc *widgets.Aerc, args []string) error {
	if len(Recover{}.Complete(aerc, args)) == 0 {
		return errors.New("No messages to recover.")

	force := false

	opts, optind, err := getopt.Getopts(args, "f")
	if err != nil {
		return err
	for _, opt := range opts {
		switch opt.Option {
		case 'f':
			force = true

	if len(args) <= optind {
		return errors.New("Usage: recover [-f] <file>")

	acct := aerc.SelectedAccount()
	if acct == nil {
		return errors.New("No account selected")

	readData := func() ([]byte, error) {
		recoverFile, err := os.Open(args[optind])
		if err != nil {
			return nil, err
		defer recoverFile.Close()
		data, err := ioutil.ReadAll(recoverFile)
		if err != nil {
			return nil, err
		return data, nil
	data, err := readData()
	if err != nil {
		return err

	composer, err := widgets.NewComposer(aerc, acct,
		aerc.Config(), acct.AccountConfig(), acct.Worker(),
		"", nil, models.OriginalMail{})
	if err != nil {
		return err

	tab := aerc.NewTab(composer, "Recovered")
	composer.OnHeaderChange("Subject", func(subject string) {
		tab.Name = subject
	go composer.AppendContents(bytes.NewReader(data))

	// remove file if force flag is set
	if force {
		err = os.Remove(args[optind])
		if err != nil {
			return err

	return nil
aerc/patches: SUCCESS in 4m4s

[recover: recover emails from tempdir after a crash][0] from [Koni Marti][1]

[0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/28824
[1]: mailto:koni.marti@gmail.com

✓ #683142 SUCCESS aerc/patches/alpine-edge.yml   https://builds.sr.ht/~rjarry/job/683142
✓ #683145 SUCCESS aerc/patches/openbsd.yml       https://builds.sr.ht/~rjarry/job/683145
✓ #683144 SUCCESS aerc/patches/fedora-latest.yml https://builds.sr.ht/~rjarry/job/683144
✓ #683143 SUCCESS aerc/patches/debian-stable.yml https://builds.sr.ht/~rjarry/job/683143
Koni Marti, Jan 28, 2022 at 22:50: