Browse Source

implemented retaining of messages from non-members

drop_old_mail
Stephan Richter 3 years ago
parent
commit
d6fea067fb
  1. 2
      pom.xml
  2. 94
      src/main/java/de/srsoftware/widerhall/data/MailingList.java
  3. 20
      src/main/java/de/srsoftware/widerhall/mail/ImapClient.java
  4. 1
      src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java

2
pom.xml

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
<groupId>org.example</groupId>
<artifactId>Widerhall</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
<build>
<plugins>
<plugin>

94
src/main/java/de/srsoftware/widerhall/data/MailingList.java

@ -7,6 +7,8 @@ import de.srsoftware.widerhall.mail.SmtpClient; @@ -7,6 +7,8 @@ import de.srsoftware.widerhall.mail.SmtpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
@ -15,6 +17,7 @@ import java.io.UnsupportedEncodingException; @@ -15,6 +17,7 @@ import java.io.UnsupportedEncodingException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static de.srsoftware.widerhall.Constants.*;
@ -46,6 +49,7 @@ public class MailingList implements MessageHandler { @@ -46,6 +49,7 @@ public class MailingList implements MessageHandler {
private static final int VISIBLE = 1;
private static final int HIDDEN = 0;
private static final int DEFAULT_STATE = STATE_PENDING|STATE_HIDE_RECEIVERS;
private static final String RETAINED_FOLDER = "retained";
private final String name;
private final String email;
private int state;
@ -136,13 +140,9 @@ public class MailingList implements MessageHandler { @@ -136,13 +140,9 @@ public class MailingList implements MessageHandler {
public MailingList enable(boolean enable) throws SQLException {
if (!enable) imap.stop();
setFlag(STATE_ENABLED,enable);
if (enable) {
imap.start().addListener(this);
} else {
imap.stop();
}
if (enable) imap.start().addListener(this);
return this;
}
@ -217,7 +217,7 @@ public class MailingList implements MessageHandler { @@ -217,7 +217,7 @@ public class MailingList implements MessageHandler {
* @return
*/
public boolean isOpenFor(User user) {
if ((state & STATE_PUBLIC) > 0) return true; // all users may subscribe public mailing lists
if (hasState(STATE_PUBLIC)) return true; // all users may subscribe public mailing lists
if (user == null) return false;
try {
var member = ListMember.load(this,user);
@ -312,10 +312,33 @@ public class MailingList implements MessageHandler { @@ -312,10 +312,33 @@ public class MailingList implements MessageHandler {
} catch (SQLException e){
LOG.error("Was not able to load members of {}; Non-Delivery notification dropped!",this.email(),e);
}
} else {
storeMessage(message);
forward(message);
return;
}
Address from = message.getFrom()[0];
if (from instanceof InternetAddress internetAddress){
var senderEmail = ((InternetAddress) from).getAddress();
if (!hasState(STATE_OPEN) && !this.hashMember(senderEmail)){
retainMessage(message);
sentRetentionNotification(senderEmail);
return;
}
}
storeMessage(message);
forward(message);
}
private boolean hashMember(String senderEmail) {
if (senderEmail == null) return false;
try {
return members().stream().map(ListMember::user).map(User::email).anyMatch(senderEmail::equals);
} catch (SQLException e) {
LOG.warn("hasMember() failded for {}",email(),e);
}
return false;
}
public MailingList open(boolean open) throws SQLException {
@ -346,7 +369,29 @@ public class MailingList implements MessageHandler { @@ -346,7 +369,29 @@ public class MailingList implements MessageHandler {
return setFlag(STATE_REPLY_TO_LIST,on);
}
private void retainMessage(Message message) {
String subject = "unknown mail";
try {
subject = message.getSubject();
imap.move(message, RETAINED_FOLDER);
return;
} catch (MessagingException e){
LOG.warn("Retaining message {} failed!",subject,e);
}
try {
message.setFlag(Flags.Flag.SEEN, true);
return;
} catch (MessagingException e) {
LOG.warn("Failed to flag message {} as SEEN!",subject,e);
}
try {
LOG.error("Retaining message {} failed. To avoid dead loop, the MailingList '{}' will be stopped!",subject,email());
enable(false);
} catch (SQLException sqle) {
LOG.debug("Failed to update list state in database:",sqle);
}
}
/**
* creates a map of the current ML containing all fields but passwords.
* @return
@ -402,7 +447,30 @@ public class MailingList implements MessageHandler { @@ -402,7 +447,30 @@ public class MailingList implements MessageHandler {
var config = Configuration.instance();
var url = new StringBuilder(config.baseUrl()).append("/confirm?token=").append(token);
var text = t("Please go to {} in order to complete your list subscription!",url);
smtp.login().send(email(),name(),user.email(),subject,text);
smtp.send(email(),name(),user.email(),subject,text);
}
private void sentRetentionNotification(String senderEmail) {
try {
var receivers = members()
.stream()
.filter(ListMember::isOwner)
.map(ListMember::user)
.map(User::email)
.collect(Collectors.joining(", "));
var subject = t("List '{}' requires attention!",name());
var text = t("This list received an email from {}, who is not member of the list.\nThe email has been moved to the '{}' folder.\nYou may manually forward this message or drop it.",senderEmail,RETAINED_FOLDER);
smtp.send(email(), name(), receivers,subject,text);
subject = t("Your message to {} was rejected!",email());
text = t("You have tried to send a message to the list '{}', which failed. This is because you are not a member of this list.\n",name());
if (hasState(STATE_PUBLIC)) text += t("You may go to {} and subscribe to the list, then try again.",Configuration.instance().baseUrl());
smtp.send(email(), name(), senderEmail,subject,text);
} catch (SQLException e){
LOG.error("Failed to load list of owners of mailing list. Retention notification was not sent to owners of {}",email(),e);
} catch (MessagingException | UnsupportedEncodingException e){
LOG.error("Failed to send retention notification to owners of {}",email(),e);
}
}
private MailingList setFlag(int flag, boolean on) throws SQLException {
@ -416,6 +484,10 @@ public class MailingList implements MessageHandler { @@ -416,6 +484,10 @@ public class MailingList implements MessageHandler {
if (hasState(STATE_ENABLED)) map.put("enabled",VISIBLE);
if (hasState(STATE_PUBLIC)) map.put("public",VISIBLE);
if (hasState(STATE_FORWARD_FROM)) map.put("original_from",HIDDEN);
if (hasState(STATE_FORWARD_ATTACHED)) map.put("forward_attached",HIDDEN);
if (hasState(STATE_HIDE_RECEIVERS)) map.put("hide_receivers",HIDDEN);
if (hasState(STATE_REPLY_TO_LIST)) map.put("reply_to_list",HIDDEN);
if (hasState(STATE_OPEN)) map.put("open",VISIBLE);
return map;
}

20
src/main/java/de/srsoftware/widerhall/mail/ImapClient.java

@ -23,6 +23,7 @@ public class ImapClient { @@ -23,6 +23,7 @@ public class ImapClient {
private static final Logger LOG = LoggerFactory.getLogger(ListeningThread.class);
private HashSet<MessageHandler> listeners = new HashSet<>();
private boolean stopped = false;
private Session session;
public ListeningThread addListener(MessageHandler messageHandler) {
listeners.add(messageHandler);
@ -53,7 +54,7 @@ public class ImapClient { @@ -53,7 +54,7 @@ public class ImapClient {
private void openInbox() throws MessagingException {
LOG.debug("Connecting and logging in…");
Properties props = imapProps();
Session session = Session.getInstance(props);
session = Session.getInstance(props);
Store store = session.getStore(Constants.IMAPS);
store.connect(host,username,password);
LOG.debug("Connected, opening {}:",folderName);
@ -75,6 +76,8 @@ public class ImapClient { @@ -75,6 +76,8 @@ public class ImapClient {
for (Message message : inbox.getMessages()){
if (message.isSet(Flags.Flag.SEEN)) continue;
handle(message);
Folder folder = message.getFolder();
if (!folder.isOpen()) folder.open(Folder.READ_WRITE);
message.setFlag(Flags.Flag.SEEN,true);
}
}
@ -158,6 +161,21 @@ public class ImapClient { @@ -158,6 +161,21 @@ public class ImapClient {
return folderName;
}
public ImapClient move(Message message, String destinationFolder) throws MessagingException {
if (listeningThread == null || listeningThread.stopped) throw new IllegalStateException("IMAP client not connected!");
var source = message.getFolder();
if (!source.isOpen()) source.open(Folder.READ_WRITE);
var messages = new Message[]{message};
var store = source.getStore();
var dest = store.getFolder(new URLName(destinationFolder));
if (!dest.exists()) dest.create(Folder.HOLDS_MESSAGES);
source.copyMessages(messages,dest);
source.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
source.close(true);
return this;
}
public ImapClient start() {
stop();

1
src/main/java/de/srsoftware/widerhall/mail/SmtpClient.java

@ -92,6 +92,7 @@ public class SmtpClient { @@ -92,6 +92,7 @@ public class SmtpClient {
}
public void send(String senderAdress, String senderName, String receivers, String subject, String content) throws MessagingException, UnsupportedEncodingException {
login();
MimeMessage message = new MimeMessage(session);
message.addHeader("Content-Type","text/plain; charset="+UTF8);
message.addHeader("format","flowed");

Loading…
Cancel
Save