Enhance e-mail invitations
- Built-in e-mail template - More template placeholders
This commit is contained in:
@@ -234,9 +234,25 @@ invite:
|
||||
# The display name used in the e-mail
|
||||
name: "Matrix Identity"
|
||||
|
||||
# The MIME content to send, UTF-8 expected
|
||||
# The E-mail template to use.
|
||||
#
|
||||
# The template is expected to be a full e-mail body, including client headers, using MIME and UTF-8 encoding.
|
||||
# The following headers will be set by mxisd directly and should not be present in the template:
|
||||
# - From
|
||||
# - To
|
||||
# - Date
|
||||
# - Message-Id
|
||||
# - X-Mailer
|
||||
#
|
||||
# The following placeholders are possible:
|
||||
# - %SENDER_DISPLAY_NAME%
|
||||
# - %ROOM_NAME%
|
||||
contentPath: "/absolute/path/to/file"
|
||||
# - %DOMAIN% Domain name as per server.name config item
|
||||
# - %DOMAIN_PRETTY% Word capitalize version of the domain. e.g. example.org -> Example.org
|
||||
# - %FROM_EMAIL% Value of this section's email config item
|
||||
# - %FROM_NAME% Value of this section's name config item
|
||||
# - %SENDER_ID% Matrix ID of the invitation sender
|
||||
# - %SENDER_NAME% Display name of the invitation sender, empty if not available
|
||||
# - %SENDER_NAME_OR_ID% Value of %SENDER_NAME% or, if empty, value of %SENDER_ID%
|
||||
# - %ROOM_ID% ID of the room where the invitation took place
|
||||
# - %ROOM_NAME% Name of the room, empty if not available
|
||||
# - %ROOM_NAME_OR_ID% Value of %ROOM_NAME% or, if empty, value of %ROOM_ID%
|
||||
template: "/absolute/path/to/file"
|
||||
|
@@ -42,7 +42,7 @@ public class EmailSenderConfig {
|
||||
private String password;
|
||||
private String email;
|
||||
private String name;
|
||||
private String contentPath;
|
||||
private String template;
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
@@ -100,12 +100,12 @@ public class EmailSenderConfig {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getContentPath() {
|
||||
return contentPath;
|
||||
public String getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public void setContentPath(String contentPath) {
|
||||
this.contentPath = contentPath;
|
||||
public void setTemplate(String template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@@ -117,14 +117,18 @@ public class EmailSenderConfig {
|
||||
log.info("Login: {}", getLogin());
|
||||
log.info("Has password: {}", StringUtils.isBlank(getPassword()));
|
||||
log.info("E-mail: {}", getEmail());
|
||||
if (StringUtils.isBlank(getContentPath())) {
|
||||
log.warn("invite.sender.contentPath is empty! Will not send invites");
|
||||
} else {
|
||||
File cp = new File(getContentPath()).getAbsoluteFile();
|
||||
log.info("Content path: {}", cp.getAbsolutePath());
|
||||
if (!cp.exists() || !cp.isFile() || !cp.canRead()) {
|
||||
log.warn(getContentPath() + " does not exist, is not a file or cannot be read");
|
||||
if (!StringUtils.startsWith(getTemplate(), "classpath:")) {
|
||||
if (StringUtils.isBlank(getTemplate())) {
|
||||
log.warn("invite.sender.template is empty! Will not send invites");
|
||||
} else {
|
||||
File cp = new File(getTemplate()).getAbsoluteFile();
|
||||
log.info("Template: {}", cp.getAbsolutePath());
|
||||
if (!cp.exists() || !cp.isFile() || !cp.canRead()) {
|
||||
log.warn(getTemplate() + " does not exist, is not a file or cannot be read");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("Template: Built-in");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -137,7 +137,7 @@ public class InvitationManager {
|
||||
|
||||
ThreePid pid = new ThreePid(invitation.getMedium(), invitation.getAddress());
|
||||
|
||||
log.info("Storing invite for {}:{} from {} in room {}", pid.getMedium(), pid.getAddress(), invitation.getSender(), invitation.getRoomId());
|
||||
log.info("Handling invite for {}:{} from {} in room {}", pid.getMedium(), pid.getAddress(), invitation.getSender(), invitation.getRoomId());
|
||||
if (invitations.containsKey(pid)) {
|
||||
log.info("Invite is already pending for {}:{}, returning data", pid.getMedium(), pid.getAddress());
|
||||
return invitations.get(pid);
|
||||
|
@@ -22,13 +22,17 @@ package io.kamax.mxisd.invitation.sender;
|
||||
|
||||
import com.sun.mail.smtp.SMTPTransport;
|
||||
import io.kamax.matrix.ThreePidMedium;
|
||||
import io.kamax.mxisd.config.ServerConfig;
|
||||
import io.kamax.mxisd.config.invite.sender.EmailSenderConfig;
|
||||
import io.kamax.mxisd.exception.ConfigurationException;
|
||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@@ -37,7 +41,6 @@ import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -51,6 +54,12 @@ public class EmailInviteSender implements IInviteSender {
|
||||
@Autowired
|
||||
private EmailSenderConfig cfg;
|
||||
|
||||
@Autowired
|
||||
private ServerConfig srvCfg;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext app;
|
||||
|
||||
private Session session;
|
||||
private InternetAddress sender;
|
||||
|
||||
@@ -77,16 +86,30 @@ public class EmailInviteSender implements IInviteSender {
|
||||
}
|
||||
|
||||
try {
|
||||
String templateBody = IOUtils.toString(new FileInputStream(cfg.getContentPath()), StandardCharsets.UTF_8);
|
||||
templateBody =
|
||||
templateBody.replace("%SENDER_DISPLAY_NAME%", invite.getInvite().getProperties().get("sender_display_name"))
|
||||
.replace("%ROOM_NAME%", invite.getInvite().getProperties().get("room_name"));
|
||||
String domainPretty = WordUtils.capitalizeFully(srvCfg.getName());
|
||||
String senderName = invite.getInvite().getProperties().getOrDefault("sender_display_name", "");
|
||||
String senderNameOrId = StringUtils.defaultIfBlank(senderName, invite.getInvite().getSender().getId());
|
||||
String roomName = invite.getInvite().getProperties().getOrDefault("room_name", "");
|
||||
String roomNameOrId = StringUtils.defaultIfBlank(roomName, invite.getInvite().getRoomId());
|
||||
|
||||
String templateBody = IOUtils.toString(app.getResource(cfg.getTemplate()).getInputStream(), StandardCharsets.UTF_8);
|
||||
templateBody = templateBody.replace("%DOMAIN%", srvCfg.getName());
|
||||
templateBody = templateBody.replace("%DOMAIN_PRETTY%", domainPretty);
|
||||
templateBody = templateBody.replace("%FROM_EMAIL%", cfg.getEmail());
|
||||
templateBody = templateBody.replace("%FROM_NAME%", cfg.getName());
|
||||
templateBody = templateBody.replace("%SENDER_ID%", invite.getInvite().getSender().getId());
|
||||
templateBody = templateBody.replace("%SENDER_NAME%", senderName);
|
||||
templateBody = templateBody.replace("%SENDER_NAME_OR_ID%", senderNameOrId);
|
||||
templateBody = templateBody.replace("%ROOM_ID%", invite.getInvite().getRoomId());
|
||||
templateBody = templateBody.replace("%ROOM_NAME%", roomName);
|
||||
templateBody = templateBody.replace("%ROOM_NAME_OR_ID%", roomNameOrId);
|
||||
|
||||
MimeMessage msg = new MimeMessage(session, IOUtils.toInputStream(templateBody, StandardCharsets.UTF_8));
|
||||
msg.setHeader("X-Mailer", "mxisd"); // TODO set version
|
||||
msg.setSentDate(new Date());
|
||||
msg.setFrom(sender);
|
||||
msg.setRecipients(Message.RecipientType.TO, invite.getInvite().getAddress());
|
||||
msg.saveChanges();
|
||||
|
||||
log.info("Sending invite to {} via SMTP using {}:{}", invite.getInvite().getAddress(), cfg.getHost(), cfg.getPort());
|
||||
SMTPTransport transport = (SMTPTransport) session.getTransport("smtp");
|
||||
|
@@ -1,3 +1,11 @@
|
||||
logging:
|
||||
level:
|
||||
org:
|
||||
springframework: "WARN"
|
||||
apache:
|
||||
catalina: "WARN"
|
||||
directory: "WARN"
|
||||
|
||||
server:
|
||||
port: 8090
|
||||
|
||||
@@ -18,16 +26,17 @@ lookup:
|
||||
ldap:
|
||||
enabled: false
|
||||
|
||||
firebase:
|
||||
enabled: false
|
||||
|
||||
forward:
|
||||
servers:
|
||||
- "https://matrix.org"
|
||||
- "https://vector.im"
|
||||
|
||||
firebase:
|
||||
enabled: false
|
||||
|
||||
invite:
|
||||
sender:
|
||||
email:
|
||||
tls: 1
|
||||
name: "mxisd Identity Server"
|
||||
template: "classpath:email/invite-template.eml"
|
||||
|
91
src/main/resources/email/invite-template.eml
Normal file
91
src/main/resources/email/invite-template.eml
Normal file
@@ -0,0 +1,91 @@
|
||||
Subject: You have been invited to %DOMAIN%
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/alternative;
|
||||
boundary="7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ"
|
||||
|
||||
--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Disposition: inline
|
||||
|
||||
Hi,
|
||||
|
||||
%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on
|
||||
Matrix. To join the conversation, register an account on http://%DOMAIN%
|
||||
|
||||
|
||||
About Matrix:
|
||||
|
||||
Matrix is an open standard for interoperable, decentralised, real-time communication
|
||||
over IP, supporting group chat, file transfer, voice and video calling, integrations to
|
||||
other apps, bridges to other communication systems and much more. It can be used to power
|
||||
Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication.
|
||||
|
||||
Thanks,
|
||||
|
||||
%DOMAIN_PRETTY% Admins
|
||||
|
||||
--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ
|
||||
Content-Type: multipart/related;
|
||||
boundary="M3yzHl5YZehm9v4bAM8sKEdcOoVnRnKR";
|
||||
type="text/html"
|
||||
|
||||
--M3yzHl5YZehm9v4bAM8sKEdcOoVnRnKR
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Disposition: inline
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
#page {
|
||||
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
|
||||
font-color: #454545;
|
||||
font-size: 12pt;
|
||||
width: 100%%;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#inner {
|
||||
width: 640px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table id="page">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td id="inner">
|
||||
<p>Hi,</p>
|
||||
|
||||
<p>%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on
|
||||
Matrix. To join the conversation, register an account on <a href="http://%DOMAIN%">%DOMAIN%</a>.</p>
|
||||
|
||||
<br>
|
||||
<p>About Matrix:</p>
|
||||
|
||||
<p>Matrix is an open standard for interoperable, decentralised, real-time communication
|
||||
over IP, supporting group chat, file transfer, voice and video calling, integrations to
|
||||
other apps, bridges to other communication systems and much more. It can be used to power
|
||||
Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication.</p>
|
||||
|
||||
<p>Thanks,</p>
|
||||
|
||||
<p>%DOMAIN_PRETTY% Admins</p>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
--M3yzHl5YZehm9v4bAM8sKEdcOoVnRnKR--
|
||||
|
||||
--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ--
|
Reference in New Issue
Block a user