Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ open class PollDO : DefaultBaseDO() {
@get:Column(name = "inputFields", length = 1000)
open var inputFields: String? = null

@PropertyInfo(i18nKey = "poll.customemailsubject")
@get:Column(name = "custom_email_subject", length = 1000)
open var customemailsubject: String? = null

@PropertyInfo(i18nKey = "poll.customemailcontent")
@get:Column(name = "custom_email_content", length = 10000)
open var customemailcontent: String? = null

@PropertyInfo(i18nKey = "poll.customReminderSubject")
@get:Column(name = "custom_reminder_subject", length = 1000)
open var customReminderSubject: String? = null

@PropertyInfo(i18nKey = "poll.customReminderContent")
@get:Column(name = "custom_reminder_content", length = 10000)
open var customReminderContent: String? = null

@PropertyInfo(i18nKey = "poll.state")
@get:Column(name = "state", nullable = false)
open var state: State = State.RUNNING
Expand Down
157 changes: 115 additions & 42 deletions projectforge-business/src/main/kotlin/org/projectforge/mail/SendMail.kt
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,42 @@ open class SendMail {
return true
}

/**
* Send email with CC recipients as BCC (for Poll emails)
* @param composedMessage the message to send
* @param icalContent the ical content to add
* @param attachments other attachments to add
* @return true for successful sending, otherwise an exception will be thrown.
* @throws UserException if to address is not given.
* @throws InternalErrorException due to technical failures.
*/
@JvmOverloads
fun sendBcc(
composedMessage: Mail?,
icalContent: String? = null,
attachments: Collection<IMailAttachment>? = null,
async: Boolean = true
): Boolean {
if (composedMessage == null) {
log.error("No message object of type org.projectforge.mail.Mail given. E-Mail not sent.")
return false
}
if (!isConfigured) {
log.error { "Sending of mails is not configured. Mail is ignored: $composedMessage" }
}
val to = composedMessage.to
if (to == null || to.size == 0) {
log.error("No to address given. Sending of mail cancelled: $composedMessage")
throw UserException("mail.error.missingToAddress")
}
if (async) {
CompletableFuture.runAsync { sendItBcc(composedMessage, icalContent, attachments) }
} else {
sendItBcc(composedMessage, icalContent, attachments)
}
return true
}

val isConfigured: Boolean
get() = this.mailingEnabled == "true" && !this.mailSmtpHost.isNullOrBlank()

Expand Down Expand Up @@ -212,61 +248,98 @@ open class SendMail {
) {
log.info("Start sending e-mail message: " + StringUtils.join(composedMessage.to, ", "))
try {
val session = session
/*if (SystemStatus.isDevelopmentMode()) {
session!!.setDebug(true)
}*/
val message = MimeMessage(session)
if (composedMessage.from != null) {
message.setFrom(InternetAddress(composedMessage.from))
} else {
mailFromStandardEmailSender
?.takeIf { it.isNotBlank() }
?.let { message.setFrom(InternetAddress(it)) }
?: message.setFrom()
}
message.setRecipients(
Message.RecipientType.TO,
composedMessage.to.toTypedArray<Address>()
)
val message = prepareMessage(composedMessage, icalContent, attachments)
// Normal behavior: Send CC as CC
if (CollectionUtils.isNotEmpty(composedMessage.cc)) {
message.setRecipients(
Message.RecipientType.CC,
composedMessage.cc.toTypedArray<Address>()
)
}
//message.setHeader("Return-Path", "")
//message.setHeader("Reply-To", "")
val subject = composedMessage.subject
message.setSubject(subject, CHARSET)
message.sentDate = Date()
if (StringUtils.isBlank(icalContent) && attachments == null) {
// create message without attachments
if (composedMessage.contentType != null) {
message.setText(composedMessage.content, composedMessage.charset, composedMessage.contentType)
} else {
message.setText(composedMessage.content, CHARSET)
}
// message.setContent("Dies ist eine einfache Testnachricht.", "text/plain; charset=UTF-8");
// message.setText("Einfache Textnachricht")
} else {
// create message with attachments
val mp = createMailAttachmentContent(message, composedMessage, icalContent, attachments, CHARSET)
message.setContent(mp)
}
message.saveChanges() // don't forget this
if (testMode) {
log.info("Test mode, do not really send e-mails (OK only for test cases).")
} else {
Transport.send(message)
}
sendMessage(message)
} catch (ex: Exception) {
log.error("While creating and sending message: $composedMessage", ex)
throw InternalErrorException("mail.error.exception")
}
log.info("E-Mail successfully sent: $composedMessage")
}

private fun sendItBcc(
composedMessage: Mail, icalContent: String?,
attachments: Collection<IMailAttachment>?
) {
log.info("Start sending e-mail message (BCC): " + StringUtils.join(composedMessage.to, ", "))
try {
val message = prepareMessage(composedMessage, icalContent, attachments)
if (CollectionUtils.isNotEmpty(composedMessage.cc)) {
message.setRecipients(
Message.RecipientType.BCC,
composedMessage.cc.toTypedArray<Address>()
)
}
sendMessage(message)
} catch (ex: Exception) {
log.error("While creating and sending message: $composedMessage", ex)
throw InternalErrorException("mail.error.exception")
}
log.info("E-Mail successfully sent (BCC): $composedMessage")
}

/**
* Prepare MimeMessage with common settings (from, to, subject, content, attachments)
*/
private fun prepareMessage(
composedMessage: Mail,
icalContent: String?,
attachments: Collection<IMailAttachment>?
): MimeMessage {
val session = session
val message = MimeMessage(session)
if (composedMessage.from != null) {
message.setFrom(InternetAddress(composedMessage.from))
} else {
mailFromStandardEmailSender
?.takeIf { it.isNotBlank() }
?.let { message.setFrom(InternetAddress(it)) }
?: message.setFrom()
}
message.setRecipients(
Message.RecipientType.TO,
composedMessage.to.toTypedArray<Address>()
)

val subject = composedMessage.subject
message.setSubject(subject, CHARSET)
message.sentDate = Date()

if (StringUtils.isBlank(icalContent) && attachments == null) {
// create message without attachments
if (composedMessage.contentType != null) {
message.setText(composedMessage.content, composedMessage.charset, composedMessage.contentType)
} else {
message.setText(composedMessage.content, CHARSET)
}
} else {
// create message with attachments
val mp = createMailAttachmentContent(message, composedMessage, icalContent, attachments, CHARSET)
message.setContent(mp)
}

message.saveChanges()
return message
}

/**
* Send the prepared MimeMessage
*/
private fun sendMessage(message: MimeMessage) {
if (testMode) {
log.info("Test mode, do not really send e-mails (OK only for test cases).")
} else {
Transport.send(message)
}
}

@Throws(MessagingException::class)
private fun createMailAttachmentContent(
message: MimeMessage, composedMessage: Mail, icalContent: String?,
Expand Down
23 changes: 18 additions & 5 deletions projectforge-business/src/main/resources/I18nResources.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2118,7 +2118,12 @@ poll.attendee=Attendee
poll.attendees=Attendees
poll.attendees.tooltip=Attendees can only vote.
poll.button.addQuestion=Add own question
poll.button.addTextQuestion=+ Free Text Question
poll.button.addSingleChoiceQuestion=+ Single Choice Question
poll.button.addMultipleChoiceQuestion=+ Multiple Choice Question
poll.button.finish=Finish Poll
poll.template.description=Select one of our templates to add a pre-configured questionnaire.
poll.question.add.description=Add individual questions here. Available types: Free text answer, Single Choice, or Multiple Choice. Your question will be appended at the end of the list.
poll.button.template=Use Template
poll.confirmation.creation=Do you really want to create the poll? You won't be able to edit the questions afterwards.\
Also make sure to add attendees for your poll.
Expand All @@ -2131,11 +2136,18 @@ poll.deadline=Deadline
poll.delegationAnswers=Answers of
poll.description=Description
poll.email-content-field=Email Content
poll.email-content-tooltip=Here you can define the content of the email. Use {0} to call the title of the poll. With {1} you can display the creator of the poll, with {2} you create a direct link to the poll. Use {3} to retrieve the description of the poll, and {4} to automatically fetch the poll''s end date, i.e., the voting deadline.
poll.email-content-tooltip=Here you can determine the content of the email yourself. Placeholders: {0}=Poll Title, {1}=Creator Name, {2}=Deadline Date, {3}=Link to Poll (HTML), {4}=Description
poll.email-subject-field=Email Subject
poll.email-subject-tooltip=Here you can choose the subject of the email yourself. Use {0} to insert the survey title and {1} to set the automatic end date of the survey - which is the deadline for voting. \
poll.email-content-tooltip=Here you can determine the content of the email yourself. Use {0} to call the survey title. With {1}, you can display the survey creator, with {2} you create a direct link to the survey.\
\ Use {3} to retrieve the survey description, and {4} to automatically retrieve the end date of the survey, i.e., the deadline for voting.
poll.email-subject-tooltip=Here you can choose the subject of the email yourself. Placeholders: {0}=Poll Title, {1}=Creator Name, {2}=Deadline Date, {3}=Link to Poll (HTML), {4}=Description
poll.email-reminder-subject-field=Reminder Email Subject
poll.email-reminder-subject-tooltip=Subject of the reminder email. Placeholders: {0}=Poll Title, {1}=Creator Name, {2}=Deadline Date, {3}=Link to Poll (HTML)
poll.email-reminder-content-field=Reminder Email Content
poll.email-reminder-content-tooltip=Content of the reminder email. Placeholders: {0}=Poll Title, {1}=Creator Name, {2}=Deadline Date, {3}=Link to Poll (HTML)
poll.mail.endingSoon.subject.default=Poll "{0}" ending soon
poll.mail.endingSoon.content.default=Dear participants,\n\nThis is a friendly reminder that the poll "{0}", created by {1}, is ending soon and will close on {2}. Please make sure to submit your responses in time.\n\n{3}\n\nBest regards\n{1}
poll.mail.link.text=Link to Poll
poll.mail.created.subject.default=You have been invited to a poll titled "{0}".
poll.mail.created.content.default=Dear participants,\n\nWe would like to inform you that a poll has been created with the title "{0}", and you have been cordially invited to participate.\n\nThe poll you have been invited to ends on {2}. A brief description of the topic can be found here: "{4}"\n\n{3}\n\nBest regards\n{1}
poll.error.cantremoveyourself=You cannot remove yourself as a Full Access User. Please ask another Full Access User or the poll creator to do this for you.
poll.error.oneAttendeeRequired=Please add at least one participant.
poll.error.oneQuestionRequired=At least one question is required.
Expand All @@ -2154,6 +2166,7 @@ poll.groupAttendees.tooltip=Group attendees are a convenient way to add entire g
poll.guide=Poll Guide
poll.headline.generalConfiguration=General settings
poll.headline.mailConfiguration=Mail settings
poll.headline.reminderMailConfiguration=Reminder Mail settings
poll.headline.questionConfiguration=Question settings
poll.headline.userConfiguration=User management
poll.infopage=Info Page
Expand Down Expand Up @@ -2207,7 +2220,7 @@ poll.manual.title=Guide to Creating a Poll | First, you need to fill in the main
poll.other=Other
poll.owner=Owner
poll.popup.closed=The poll was already closed.
poll.premade.template=Add Template
poll.premade.template=Add questions from template
poll.premadeQuestion.tooltip=In this menu, you will find frequently used templates that help you create the survey quickly. If questions are missing in the template, you can also add them. Additionally,\
\ you have the option to revise or correct questions if they do not apply to your situation in the template.
poll.question=Question
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2204,7 +2204,12 @@ poll.attendee=Teilnehmer:in
poll.attendees=Teilnehmer:innen
poll.attendees.tooltip=Teilnehmer:innen können nur abstimmen.
poll.button.addQuestion=Eigene Frage hinzufügen
poll.button.addTextQuestion=+ Freitext Frage
poll.button.addSingleChoiceQuestion=+ Single Choice Frage
poll.button.addMultipleChoiceQuestion=+ Multiple Choice Frage
poll.button.finish=Umfrage beenden
poll.template.description=Wählen Sie eine unserer Vorlagen, um einen vorgefertigten Fragebogen hinzuzufügen.
poll.question.add.description=Fügen Sie hier einzelne Fragen hinzu. Verfügbare Typen: Freitextantwort, Single Choice oder Multiple Choice. Ihre Frage wird am Ende der Liste angehängt.
poll.button.template=Vorlage verwenden
poll.confirmation.creation=Möchtest du die Umfrage wirklich erstellen? Du kannst die Fragen danach nicht mehr bearbeiten.\
Stelle ebenfalls sicher, dass du Teilnehmer:innen für deine Umfrage hinzugefügt hast.
Expand All @@ -2217,10 +2222,18 @@ poll.deadline=Antwortfrist
poll.delegationAnswers=Antworten von
poll.description=Beschreibung
poll.email-content-field=E-Mail Inhalt
poll.email-content-tooltip=Du kannst den Inhalt der E-Mail individuell gestalten, indem du Platzhalter verwendest. Nutze {0}, um den Titel der Umfrage einzufügen. Mit {1} kannst du den Namen des Erstellers der Umfrage anzeigen, und {2} fügt einen direkten Link zur Umfrage ein. \
Um die Beschreibung der Umfrage hinzuzufügen, verwende {3}, und mit {4} kannst du das Enddatum der Umfrage automatisch einfügen, das als Deadline für die Abstimmung dient.
poll.email-content-tooltip=Du kannst den Inhalt der E-Mail individuell gestalten, indem du Platzhalter verwendest. Platzhalter: {0}=Umfrage-Titel, {1}=Ersteller-Name, {2}=Deadline-Datum, {3}=Link zur Umfrage (HTML), {4}=Beschreibung
poll.email-subject-field=Email Titel
poll.email-subject-tooltip=Hier kannst du den Betreff der E-Mail selbst angeben. Verwende {0}, um den Titel der Umfrage einzufügen, und {1}, um das automatische Enddatum der Umfrage einzusetzen
poll.email-subject-tooltip=Hier kannst du den Betreff der E-Mail selbst angeben. Platzhalter: {0}=Umfrage-Titel, {1}=Ersteller-Name, {2}=Deadline-Datum, {3}=Link zur Umfrage (HTML), {4}=Beschreibung
poll.email-reminder-subject-field=Erinnerungsmail Titel
poll.email-reminder-subject-tooltip=Betreff der Erinnerungsmail. Platzhalter: {0}=Umfrage-Titel, {1}=Ersteller-Name, {2}=Deadline-Datum, {3}=Link zur Umfrage (HTML)
poll.email-reminder-content-field=Erinnerungsmail Inhalt
poll.email-reminder-content-tooltip=Inhalt der Erinnerungsmail. Platzhalter: {0}=Umfrage-Titel, {1}=Ersteller-Name, {2}=Deadline-Datum, {3}=Link zur Umfrage (HTML)
poll.mail.endingSoon.subject.default=Umfrage "{0}" endet bald
poll.mail.endingSoon.content.default=Liebe Teilnehmerinnen und Teilnehmer,\n\ndies ist eine freundliche Erinnerung, dass die Umfrage "{0}", erstellt von {1}, bald endet und am {2} geschlossen wird. Bitte stellen Sie sicher, dass Sie Ihre Antworten rechtzeitig einreichen.\n\n{3}\n\nMit freundlichen Grüßen\n{1}
poll.mail.link.text=Link zur Umfrage
poll.mail.created.subject.default=Sie wurden zu einer Umfrage mit dem Titel "{0}" eingeladen.
poll.mail.created.content.default=Liebe Teilnehmer:innen,\n\nWir möchten Ihnen mitteilen, dass eine Umfrage erstellt wurde mit dem Titel "{0}", und Sie wurden herzlichst eingeladen bei dieser abzustimmen.\n\nDie Umfrage, zu welcher Sie eingeladen wurden, endet am {2}. Eine kurze Beschreibung des Themas finden Sie hier: "{4}"\n\n{3}\n\nMit freundlichen Grüßen\n{1}
poll.error.cantremoveyourself=Du kannst dich nicht selbst als Full Access User entfernen. Bitte einen anderen Full Access User oder den/die Ersteller:in dieser Umfrage dies für dich zu tun.
poll.error.oneAttendeeRequired=Bitte füge mindestens eine:n Teilnehmer:in hinzu.
poll.error.oneQuestionRequired=Mindestens eine Frage ist erforderlich.
Expand All @@ -2239,6 +2252,7 @@ poll.groupAttendees.tooltip=Teilnehmergruppen bieten dir die Möglichkeit, nicht
poll.guide=Anleitung
poll.headline.generalConfiguration=Allgemeine Einstellungen
poll.headline.mailConfiguration=E-Mail Einstellungen
poll.headline.reminderMailConfiguration=Erinnerungsmail Einstellungen
poll.headline.questionConfiguration=Hinzufügen von Fragen
poll.headline.userConfiguration=Nutzer:innen Verwaltung
poll.infopage=Infoseite
Expand Down Expand Up @@ -2290,7 +2304,7 @@ poll.manual.title=Anleitung, um eine Umfrage zu erstellen | Als Erstes muss man
poll.other=Andere
poll.owner=Ersteller:in
poll.popup.closed=Umfrage wurde bereits beendet
poll.premade.template=Vorlage hinzufügen
poll.premade.template=Fragen aus Vorlage hinzufügen
poll.premadeQuestion.tooltip=In diesem Menü findest du häufig verwendete Vorlagen, die dir dabei helfen, deine Umfrage schnell zu erstellen. Falls Fragen in der Vorlage fehlen, kannst du sie auch hinzufügen. \
Außerdem hast du die Möglichkeit, Fragen zu überarbeiten oder zu korrigieren, wenn sie in der Vorlage nicht auf deine Situtation zutreffen.
poll.question=Frage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class Poll(
var questionType: String? = null,
var customemailsubject: String? = null,
var customemailcontent: String? = null,
var customReminderSubject: String? = null,
var customReminderContent: String? = null,
var prequestionType: String? = null,
var inputFields: MutableList<Question>? = mutableListOf(),
var fullAccessGroups: List<Group>? = null,
Expand Down
Loading