【问题标题】:how to send email (spawn mail) from gjs gtk app如何从 gjs gtk 应用程序发送电子邮件(生成邮件)
【发布时间】:2019-01-26 11:54:23
【问题描述】:

我正在尝试编写一个需要发送电子邮件的 gjs 应用程序。 我发现这样做的方法是使用 spawn_async_with_pipes() 来调用邮件。 该应用程序似乎生成了邮件,我没有收到错误消息,但我没有得到任何有用的输出,也没有收到测试电子邮件...

我在这方面已经有一段时间了,几乎没有发现任何有用的最新文档。我正在使用 gtk3 和 gjs(以及 glib)。我还尝试生成一个 shell 脚本,该脚本反过来调用邮件。这导致“无法解析主机”错误和死信队列。所以我知道我正在产生我的命令。我并不担心“无法解析主机命令”,而是因为我无法通过直接生成邮件来获取它。

我正在生成这样的邮件:

const [res, pid, in_fd, out_fd, err_fd] =
await GLib.spawn_async_with_pipes(null,
                                              ['mail',
                                              '-V',
                                              `-s "${msgObj.subBlock}"`,
                                              `-r ${to}`,
                                              `-S smtp=${HOST}`,
                                              '-S smtp-use-starttls',
                                              '-S smtp-auth=login',
                                              `-S smtp-auth-user=${USER}`,
                                              `-S smtp-auth-password=${PASS}`,
                                              FROM
                                              ], null, GLib.SpawnFlags.SEARCH_PATH, null);

const in_reader = new Gio.DataOutputStream({
        base_stream: new Gio.UnixOutputStream({fd: in_fd})
      });
      var feedRes = in_reader.put_string(msgObj.msgBlock, null);

      const out_reader = new Gio.DataInputStream({
        base_stream: new Gio.UnixInputStream({fd: out_fd})
      });
      const err_reader = new Gio.DataInputStream({
        base_stream: new Gio.UnixInputStream({fd: err_fd})
      });
      var out = out_reader.read_until("", null);
      var err = err_reader.read_until("", null);

      print(` > out : "${out}"`);
      print(` > res : "${res}"`);
      print(` > feedRes : "${feedRes}"`);
      print(` > err : "${err}"`);

错误是0,而res 只是true

我不知道输出应该是什么,但我没有收到可识别的错误,也没有发送电子邮件... 如何让我的应用程序发送电子邮件?生成邮件不是要走的路吗? 提前感谢您能给我的任何指示。

【问题讨论】:

    标签: gnome gjs


    【解决方案1】:

    我认为这里有几件事让你感到困惑,我想我可以澄清一下。

    await GLib.spawn_async_with_pipes(
    

    GLib 有自己的异步函数概念,在适用时需要将其包装在 Promise 中以有效地使用 await 关键字。在这种情况下,GLib.spawn_async_with_pipes() 并不是您想的那样异步,但这没关系,因为我们将使用更高级别的类 Gio.Subprocess

    async function mail(msgObj, to, host, user, pass, cancellable = null) {
        try {
            let proc = new Gio.Subprocess({
                argv: ['mail',
                       '-V',
                       // Option switches and values are separate args
                       '-s', `"${msgObj.subBlock}"`,
                       '-r', `${to}`,
                       '-S', `smtp=${host}`,
                       '-S', 'smtp-use-starttls',
                       '-S', 'smtp-auth=login',
                       '-S', `smtp-auth-user=${user}`,
                       '-S', `smtp-auth-password=${pass}`,
                       FROM
                ],
                flags: Gio.SubprocessFlags.STDIN_PIPE |
                       Gio.SubprocessFlags.STDOUT_PIPE |
                       Gio.SubprocessFlags.STDERR_MERGE
            });
            // Classes that implement GInitable must be initialized before use, but
            // you could use Gio.Subprocess.new(argv, flags) which will call this for you
            proc.init(cancellable);
    
            // We're going to wrap a GLib async function in a Promise so we can
            // use it like a native JavaScript async function.
            //
            // You could alternatively return this Promise instead of awaiting it
            // here, but that's up to you.
            let stdout = await new Promise((resolve, reject) => {
    
                // communicate_utf8() returns a string, communicate() returns a
                // a GLib.Bytes and there are "headless" functions available as well
                proc.communicate_utf8_async(
                    // This is your stdin, which can just be a JS string
                    msgObj.msgBlock,
    
                    // we've been passing this around from the function args; you can
                    // create a Gio.Cancellable and call `cancellable.cancel()` to
                    // stop the command or any other operation you've passed it to at
                    // any time, which will throw an "Operation Cancelled" error.
                    cancellable,
    
                    // This is the GAsyncReady callback, which works like any other
                    // callback, but we need to ensure we catch errors so we can
                    // propagate them with `reject()` to make the Promise work
                    // properly
                    (proc, res) => {
                        try {
                            let [ok, stdout, stderr] = proc.communicate_utf8_finish(res);
                            // Because we used the STDERR_MERGE flag stderr will be
                            // included in stdout. Obviously you could also call
                            // `resolve([stdout, stderr])` if you wanted to keep both
                            // and separate them.
                            // 
                            // This won't affect whether the proc actually return non-
                            // zero causing the Promise to reject()
                            resolve(stdout);
                        } catch (e) {
                            reject(e);
                        }
                    }
                );
            });
    
            return stdout;
        } catch (e) {
            // This could be any number of errors, but probably it will be a GError
            // in which case it will have `code` property carrying a GIOErrorEnum
            // you could use to programmatically respond to, if desired.
            logError(e);
        }
    }
    

    Gio.Subprocess 总体上是一个更好的选择,但特别是对于不能将“输出”参数传递给函数的语言绑定。使用GLib.spawn_async_with_pipes,您通常会传入NULL,以防止打开任何您不想要的管道,并始终确保关闭任何您不想要的管道。由于我们无法在 GJS 中执行此操作,因此您最终会得到无法关闭的悬空文件描述符。

    Gio.Subprocess 为您做了很多工作,并确保文件描述符正在关闭,防止僵尸进程,为您设置子监视以及您真正不想担心的其他事情。它还具有获取 IO 流的便利功能,因此您不必自己包装 fd 以及其他有用的东西。

    我写了一篇关于 GJS 异步编程的长篇入门书 here。尽管它很快你应该能够轻而易举,它试图消除一些关于 GLib 异步、JavaScript 异步和 GLib 主循环与 JS 事件循环之间关系的混淆。

    【讨论】:

    • 感谢负载,@andy.holmes。这就像一个魅力,解释也很棒。 Gio.Subprocess 比 Spawn 清晰得多...
    猜你喜欢
    • 2013-03-13
    • 2010-12-20
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    相关资源
    最近更新 更多