<p>I want to send various emails from my website such as registration verification emails, password reset etc. All emails that should be sent on user request. </p>
<p>My current solution is to send emails from within my request handler functions, however that has resulted in long response times on those requests.</p>
<p>I'd thought of spinning up a separate routine and handling emails there, but if they fail, the server then wouldn't be able to respond with an error and the user would be none the wiser.</p>
<p>The other idea would be to have a database table that stores records of emails to be sent and a separate application that routinely checks that table for emails to be sent and goes ahead with them.</p>
<p>What are your approaches for emailing from your websites?</p>
<p>EDIT: I'm using the SendGrid API to send emails from my website. That's what's causing response times to add up.</p>
<hr/>**评论:**<br/><br/>earthboundkid: <pre><p>This is a problem that crosses language boundaries. In any language, tasks that can conceivably take longer than half a second should be added to a queue of some sort and then you can let the user know that the task is done later. For example, in Python, you would do this using a Celery-Rabbit MQ task queue.</p>
<p>Go gives you a range of solutions from the robust to the quick and dirty. At scale, you'll need some way of queueing tasks that is resilient against various kinds of failures (what if you have to restart the server in the middle of sending an email?). But for small projects or as a minimum viable project, you can probably just get away with spawning a goroutine and maybe using a websocket to tell the client that their task is done or have them ping some endpoint with AJAX that will return <code>{"taskDone": false}</code> and <code>{"taskDone": true}</code>. It's up to you to decide how robust you need your solution to be.</p>
<p>Here's an architecture that is maybe not too onerous to implement. When you need to write an email, grab the database and write a new row with the email address, body, etc. and a boolean flag for sent=false. On start up, in addition to starting your router, also start a mail demon as a goroutine. Have it connect to the database every couple hundred milliseconds, find any unsent rows, send the emails, then mark the rows as sent. This will only work as long as you have just one server running. When you have more, you'll need some way to keep the mail demons from fighting each other and sending the same email more than once, so you'll probably want to learn about Rabbit MQ or some other task queue, but it's simple enough to scrape by with this database only solution to start.</p></pre>danhardman: <pre><p>Unless it's a javascript web application, that method just isn't viable. People won't be waiting on a "Thanks for registering" page for a notification to say their email has been successfully sent. I think the queue system is definitely how it has to go, but you have pointed out that it isn't going to be as simple as I'd thought to produce such a system.</p>
<p>Are there any libraries/services for Go you might recommend or are you as new to this problem in Go as I am? </p></pre>thesnowmancometh: <pre><p>Check out Machinery by Richard Knop. It's a port of Celery to Go. However, it only communicates over HTTP, since it's dependent on an AMPQ protocol library that does not support HTTPS. </p>
<p><a href="https://github.com/richardknop/machinery" rel="nofollow">https://github.com/richardknop/machinery</a></p></pre>SaucyChug: <pre><blockquote>
<p>the server then wouldn't be able to respond with an error and the user would be none the wiser.</p>
</blockquote>
<p>I don't think that's the right approach. If your email system is broken your sysadmin needs to take a look at it, the user can't do anything about it. So just print an error and continue - a sysadmin should see the error and fix it. And if your email system is producing errors all the time - maybe you need to be using a more robust system?</p>
<p>But, if you really want to show an error message to a user, why not poll via AJAX or open a WebSocket and then stop polling/close the socket when you get a "yes the email was sent" message from the server?</p>
<blockquote>
<p>The other idea would be to have a database table that stores records of emails to be sent and a separate application that routinely checks that table for emails to be sent and goes ahead with them.</p>
</blockquote>
<p>Yep. A message queue sounds like a good solution. Or a third-party service like SES or something.</p></pre>danhardman: <pre><blockquote>
<p>the user can't do anything about it.</p>
</blockquote>
<p>True but they shouldn't assume all is well. If they register and don't get a registration email then that's a pretty big failure.</p>
<blockquote>
<p>Or a third-party service like SES or something</p>
</blockquote>
<p>I'm currently using Send Grid, that's what's making the responses take so long. That's the main issue I'm facing, not that there are errors.</p>
<p>I think message queue is the way to go. Just more to maintain...</p></pre>metamatic: <pre><p>Given that SendGrid's entire value proposition is reliability, I'd say use a separate goroutine. If you get failures, stop using SendGrid.</p></pre>ngrilly: <pre><p>You forget about the network between you and SendGrid, which can fail, independently of all SendGrid's efforts being reliable.</p></pre>danhardman: <pre><p>That was my worry. I suppose other websites simply allow the use to re-send emails they haven't received so as long as I can log errors myself, the user doesn't need to know about them.</p></pre>sethammons: <pre><p>Hey. I work at SendGrid and with our incoming servers. How long of response times are you seeing? Internally, we have a median response handling of 10ms (if I recall correctly). This makes me wonder if you are sending inordinately large messages and/or are experiencing latency just due to HTTP and distance to our closest incoming nodes, or if your volume is low and you are not hot in the cache. Feel free to email me at seth@sendgrid, I'd be interested in hearing more of your use case. Cheers!</p></pre>danhardman: <pre><p>The emails I'm sending are very small, simply to test my end-points. I'll take note of the response times and get back to you! Thanks for showing interest!</p></pre>MrRichyPants: <pre><p>I use SendGrid as well, and what I do, is a mix of these, while trying to minimize maintenance.</p>
<p>In the request handlers, I send the data/html to the user so that they get a prompt experience. Then, still in the handler, I call out to the SendGrid API to send the email.</p>
<p>I agree that the user doesn't need to know if there is an email issue, and I want to give the user a page as quickly as possible, and I don't want to have to maintain a separate system/job/queue/process to handle just sending emails.</p></pre>danhardman: <pre><p>I assume you do this in a separate go routine then?</p>
<p>I'm working with templates on my website and even if I place the SendGrid API stuff after <code>templates.ExecuteTemplate()</code>, the response still hangs until the handler returns.</p></pre>TRAPFLAG_8: <pre><p>Use a go routine for anything you don't want to wait for. (like sending email)</p></pre>atesushiforlunch: <pre><p>How does delivering mail cause long respose times?
Are you sending via an external smtp-server or something?
If so, have you tried installing something like Postfix locally and queue mails up there?</p></pre>danhardman: <pre><p>Sorry I should have made it clear in the original post, I'm using the SendGrid API to send emails.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传