Skip to content

Commit dd17b12

Browse files
committed
🐛 Fix TemplateRegistrationFailed error when sending email
Should resolve #549, and added supporting documentation
1 parent 1331426 commit dd17b12

File tree

8 files changed

+152
-9
lines changed

8 files changed

+152
-9
lines changed

crates/email/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ mod template;
1212

1313
pub use emailer::{AttachmentPayload, EmailerClient, EmailerClientConfig};
1414
pub use error::{EmailError, EmailResult};
15-
pub use template::{render_template, EmailTemplate};
15+
pub use template::{
16+
render_template, EmailTemplate, ATTACHMENT_TEMPLATE, BASE_TEMPLATE, TEMPLATES,
17+
};
1618

1719
pub use lettre::message::header::ContentType as EmailContentType;

crates/email/src/template.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ use std::path::PathBuf;
33
use crate::EmailResult;
44
use handlebars::Handlebars;
55

6+
pub static BASE_TEMPLATE: &str = include_str!("../templates/base.hbs");
7+
pub static ATTACHMENT_TEMPLATE: &str = include_str!("../templates/attachment.hbs");
8+
9+
pub static TEMPLATES: &[(&str, &str)] =
10+
&[("base", BASE_TEMPLATE), ("attachment", ATTACHMENT_TEMPLATE)];
11+
612
// TODO: expose this enumeration to the public API somehow, so that users can define their own template overrides
713

814
pub enum EmailTemplate {
@@ -19,6 +25,7 @@ impl AsRef<str> for EmailTemplate {
1925
}
2026

2127
/// Render a template to a string using the given data and templates directory.
28+
/// If the template does not exist on disk, the default template will be used.
2229
///
2330
/// # Example
2431
/// ```no_run
@@ -40,15 +47,19 @@ pub fn render_template(
4047
) -> EmailResult<String> {
4148
let mut handlebars = Handlebars::new();
4249
handlebars.register_partial("base_partial", "{{> base}}")?;
43-
handlebars.register_template_file("base", templates_dir.join("base.hbs"))?;
44-
handlebars
45-
.register_template_file("attachment", templates_dir.join("attachment.hbs"))?;
50+
51+
for (name, template) in TEMPLATES {
52+
let override_template = templates_dir.join(format!("{}.hbs", name));
53+
if override_template.exists() {
54+
handlebars.register_template_file(name, override_template)?;
55+
} else {
56+
handlebars.register_template_string(name, template)?;
57+
}
58+
}
4659

4760
Ok(handlebars.render(template.as_ref(), data)?)
4861
}
4962

50-
// TODO: Write meaningful tests
51-
5263
#[cfg(test)]
5364
mod tests {
5465
use super::*;
@@ -58,7 +69,7 @@ mod tests {
5869
}
5970

6071
#[test]
61-
fn render_template_attachment() {
72+
fn render_template_attachment_from_disk() {
6273
let data = serde_json::json!({
6374
"title": "Stump Attachment",
6475
});
@@ -69,4 +80,16 @@ mod tests {
6980

7081
assert!(rendered.contains("Stump Attachment"));
7182
}
83+
84+
#[test]
85+
fn render_default_template_attachment() {
86+
let data = serde_json::json!({
87+
"title": "Stump Attachment",
88+
});
89+
90+
let rendered =
91+
render_template(EmailTemplate::Attachment, &data, PathBuf::new()).unwrap();
92+
93+
assert!(rendered.contains("Stump Attachment"));
94+
}
7295
}

docs/pages/guides/basics/_meta.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Meta } from 'nextra'
22

33
export default {
4+
webapp: 'App',
45
books: 'Books',
56
progress: 'Book Progress',
67
readers: 'Book Readers',

docs/pages/guides/basics/webapp.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Web App
2+
3+
The web app is the default, browser-based interface for Stump. It is a single-page application (SPA) built with [React](https://react.dev/).
4+
5+
## Access
6+
7+
The web app is accessible by navigating the host machine's IP address and the configured port in a web browser. For example, if your Stump server is running on your local machine and the default port is used, you would navigate to `http://localhost:10801` in your browser. If you are attempting to access the web app from a different machine on the same network, you would navigate to `http://{machine_ip}:10801`.
8+
9+
Accessing the web app from a different machine on a different network is a bit more complicated, and a bit beyond the scope of this guide. In the future, I'd love to have some curated tutorials for common setups (e.g., using a reverse proxy, setting up a VPN, etc.). I personally use Tailscale and Caddy, but there are many ways to accomplish this.
10+
11+
If you have a specific setup you'd like to see a guide for, or are willing to share your setup with a proper how-to write-up, please reach out!

docs/pages/guides/configuration/server-options.md

+8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ The version of the Stump API to use. This should really be left alone and **not*
2222

2323
This corresponds to the `api_version` configuration option in the `Stump.toml` file.
2424

25+
### EMAIL_TEMPLATES_DIR
26+
27+
The directory where Stump will look for email templates. This is only required if you want to use custom email templates. By default, Stump will look for email templates in the `templates` directory in the root of the configuration directory. E.g., if your configuration directory is `~/.stump`, Stump will look for email templates in `~/.stump/templates`.
28+
29+
| Type | Default Value |
30+
| ------ | ------------------------ |
31+
| String | `{config_dir}/templates` |
32+
2533
#### PDFIUM_PATH
2634

2735
The path to the PDFium binary. This is only required if you want PDF support and you're running Stump outside of Docker, since the PDFium binary is included in the Docker image. You'll want to find and download the PDFium binary for your platform from [here](https://github.com/bblanchon/pdfium-binaries/releases), and then set this environment variable to the path of the binary.

docs/pages/guides/desktop/index.mdx

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import { Callout } from 'nextra/components'
33
# Desktop App
44

55
<Callout emoji="🚧">
6-
This app is not yet available for download. I expect an initial **unstable** release to be
7-
available towards the end of 2024. Expect bugs and missing features, but stay tuned for updates!
6+
At the time of writing, the desktop app has a **nightly** release available on
7+
[GitHub](https://github.com/stumpapp/stump/releases/tag/untagged-dcf8ed03bb6a19b142e0). It is not
8+
stable, will contain bugs, and not feature complete. However if you decide to try it, please
9+
report any issues you encounter!
810
</Callout>
911

1012
The very same app you use in your browser, but with added features:

docs/pages/guides/features/_meta.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Meta } from 'nextra'
33
export default {
44
'api-keys': 'API Keys',
55
'book-clubs': 'Book Clubs',
6+
email: 'Email',
67
'file-explorer': 'File Explorer',
78
upload: 'File Uploads',
89
'smart-list': 'Smart Lists',

docs/pages/guides/features/email.mdx

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { Callout } from 'nextra/components'
2+
3+
# Emailing
4+
5+
<Callout emoji="🔐">
6+
Sending emails is gated behind the `email:send` user permission at a minumum. To learn more about
7+
permissions, see the [permissions](/guides/access-control/permissions) guide.
8+
</Callout>
9+
10+
Stump has basic email functionality built-in, allowing you to send books via email. This feature was primarily developed to support email-to-ereader integrations, however there are loose plans for expanding it in the future.
11+
12+
## Emailers
13+
14+
An emailer is essentially just a named configuration object that tells Stump how to send emails from a specific email account. Stump doesn't have its own email server or client, so it relies on SMTP to send emails. This means that you'll need to provide the necessary connection and auth details to send emails.
15+
16+
### Configuration
17+
18+
The following fields are required to configure an emailer:
19+
20+
- `name` - The name of the emailer, used for display purposes throughout the app
21+
- SMTP-specifics:
22+
- `host` - The SMTP server hostname, e.g., `smtp.gmail.com`
23+
- `port` - The SMTP server port, e.g., `587`
24+
- `username` - The username for the SMTP server, e.g., an email address
25+
- `password` - The password for the SMTP server, encrypted at rest
26+
- `TLS enabled` - Whether to use a secure connection (e.g., `true` for SSL, `false` for no security)
27+
- Sender information:
28+
- `Display name` - The name that will be displayed to recipients
29+
- `Email address` - The email address that will be displayed to recipients
30+
31+
<Callout emoji="🔒">
32+
The password field is encrypted at rest and not visible after creation. Stump will decrypt the
33+
password when sending emails. This is a security measure to prevent unauthorized access to your
34+
email server. You should still take care to secure your Stump instance.
35+
</Callout>
36+
37+
You may also optionally configure the following fields:
38+
39+
- Max attachment size - The maximum size of attachments that can be sent via this emailer
40+
41+
## Device Aliases
42+
43+
A device alias refers to a named email address that can be quickly selected when sending books via email. The name is perhaps misleading, since your email doesn't necessarily have to be associated with a device. This is subject to change.
44+
45+
### Forbidden Aliases
46+
47+
A device alias may also be "inverted" to create a forbidden email address. This is useful for blocking certain email addresses from receiving books via your server. This really only comes into play when considering arbitrary send permissions, since without that permission a user would have to select from a list of device aliases which _aren't_ forbidden.
48+
49+
## Templates
50+
51+
Stump uses [handlebars](https://handlebarsjs.com/) for email templating. The default templates are very basic, but you can override them with your own custom templates. The only requirement is that you ensure the template fields align with the fields Stump expects.
52+
53+
The default templates can be found [on GitHub](https://github.com/stumpapp/stump/tree/main/crates/email/templates).
54+
55+
### Template Overrides
56+
57+
To override a template, simply create a new template with the same name in the template directory of your Stump instance. Stump will automatically use your custom template in place of the default.
58+
59+
The template directory defaults to a `templates` directory in the root of your Stump configuration directory. You can change this by setting the `EMAIL_TEMPLATES_DIR` environment variable. For more information on configuring Stump, see the [configuration](/guides/configuration/server-options) guide.
60+
61+
## Permissions
62+
63+
The following table lists perissions which can be assigned to users to control access to email functionality:
64+
65+
| Permission | Description | Notes / Inherited Permissions |
66+
| ---------------- | ---------------------------------------------- | ----------------------------- |
67+
| `emailer:read` | Allows the user to view registered emailers | |
68+
| `emailer:create` | Allows the user to create new emailers | `emailer:read` |
69+
| `emailer:manage` | Allows the user to manage existing emailers | `emailer:read` |
70+
| `email:send` | Allows the user to send emails from the server | `emailer:read` |
71+
72+
## Audit Logs
73+
74+
Stump will log each email sent, however the logs are not currently exposed in the UI. This is a planned feature, but for now you can view the logs directly in the database with your preferred SQL client.
75+
76+
The following fields are logged for each record:
77+
78+
- The ID of the emailer used
79+
- The email address the email was sent to
80+
- A JSON blob containing metadata for the attachment
81+
- The time the email was sent
82+
- The user ID of the user who sent the email
83+
84+
## Future Plans
85+
86+
The email feature is not fully fleshed out yet, and there are plans to expand it in the future. Some of the planned features revolve around:
87+
88+
- Server invitations via email, e.g., inviting users to join your server
89+
- Email notifications for various server events
90+
- Book club email notifications
91+
92+
<Callout emoji="🚀">
93+
If you have any ideas for expanding the email functionalities, feel free to open an issue on
94+
[GitHub](https://github.com/stumpapp/stump/issues)
95+
</Callout>

0 commit comments

Comments
 (0)