Communication between different EPLs

Hello all,
I have a question regarding the possibility of consolidating emails triggered by multiple EPLs into a single email.
Is there a way to create another EPL that compiles the text content of emails generated by these different EPLs to trigger a unified email?
If this is feasible, could you provide a concise example and some resources to help me get started on this?
Thank you.

Rather than sending multiple SendEmail events to the SendEmail.SEND_CHANNEL channel, you could send them to your own channel which is listened to in another EPL file that aggregates the event contents and sends an email at intervals. Here is example code using a stream query with a custom aggregate function.

using com.apama.cumulocity.SendEmail;

aggregate bounded combineEmail(SendEmail email) returns SendEmail { 
    
	integer	nextId;
	dictionary<integer, SendEmail> emailsToCombine;
    
    action init() {
    	emailsToCombine.clear();
    	nextId := 0;
    }

    action add(SendEmail email) returns integer {
    	integer id := nextId;
    	emailsToCombine.add(id, email);
    	nextId := nextId + 1;
    	return id;
    }
    
    action remove(SendEmail email, integer id) {
    	emailsToCombine.remove(id);
    }
    
    action value() returns SendEmail {
    	SendEmail combinedEmail := new SendEmail;
    	if emailsToCombine.size() > 0 {
    		SendEmail firstEmail := emailsToCombine.values()[0];
    		combinedEmail.receiver := firstEmail.receiver;
    		combinedEmail.cc := firstEmail.cc;
    		combinedEmail.bcc := firstEmail.bcc;
    		combinedEmail.subject := "Combined emails";
    		combinedEmail.text := "<table><tr><th>Subject</th><th>Text</th><tr>";
    		SendEmail email;
    		for email in emailsToCombine.values() {
    			combinedEmail.text := combinedEmail.text + "<tr><td>" + email.subject + "</td><td>" + email.text + "</td><tr>";	
    		}
    		combinedEmail.text := combinedEmail.text +  "</table>";
    	}
    	return combinedEmail;
	}
}

monitor EmailAggregator {

	constant float TIME_INTERVAL_SECONDS := 300.0; // 5 minutes
	
	action onload {
		monitor.subscribe("my_email_channel");
		
		from email in all SendEmail() within TIME_INTERVAL_SECONDS every TIME_INTERVAL_SECONDS
		  		group by email.receiver,email.cc,email.bcc select combineEmail(email) as combinedEmail {
			if (combinedEmail.receiver.size() > 0) {
				send combinedEmail to SendEmail.SEND_CHANNEL;
			}
		}
	}
	
}

Hello Joel,
I am confused on what piece of code goes to the EPL I already have and which one goes onto the new EPL I have to make.
Thank you.

I intend my EPL example code to all go into a new EPL file. Then, where you are currently sending SendEmail to SendEmail.SEND_CHANNEL in your existing EPL you could send it to the channel named in the new EPL file, currently “my_email_channel”.

What would it look like instead if I wanted to gather a bounce of string and then send these as text of an email?
Thank you and let me know.

How about this?
In one EPL file:

package com.mycompany.emailaggregation;

using com.apama.cumulocity.SendEmail;

event EmailLine {
	string text;
}

aggregate bounded createEmail(EmailLine emailLine) returns SendEmail { 
    
	integer	nextId;
	dictionary<integer, EmailLine> emailLines;
    
    action init() {
    	emailLines.clear();
    	nextId := 0;
    }

    action add(EmailLine emailLine) returns integer {
    	integer id := nextId;
    	emailLines.add(id, emailLine);
    	nextId := nextId + 1;
    	return id;
    }
    
    action remove(EmailLine emailLine, integer id) {
    	emailLines.remove(id);
    }
    
    action value() returns SendEmail {
    	SendEmail email := new SendEmail;
    	email.receiver := [ "person1@myCompany.com" ];
    	email.subject := "Update";
    	email.text := "Text lines:\r\n\r\n";
    	EmailLine emailLine;
    	for emailLine in emailLines.values() {
    		email.text := email.text + emailLine.text + "\r\n";
    	}
    	return email;
	}
}

monitor EmailAggregator {

	constant float TIME_INTERVAL_SECONDS := 300.0; // 5 minutes
	
	action onload {
		monitor.subscribe("my_email_channel");
		
		from emailLine in all EmailLine() within TIME_INTERVAL_SECONDS every TIME_INTERVAL_SECONDS
		  		select createEmail(emailLine) as combinedEmail {
			send combinedEmail to SendEmail.SEND_CHANNEL;
		}
	}	
}

From your other EPL you can then send EmailLine events:

using com.mycompany.emailaggregation.EmailLine;

monitor MyMonitor {
	action onload {
		send EmailLine("Line1") to "my_email_channel";
		send EmailLine("Line2") to "my_email_channel";
		send EmailLine("Line3") to "my_email_channel";
	}
}

Will every different device have an instance of these EPL or is it an instance only for all devices?

Also when I try to add package I get the follwoing error:

unexpected token: 'package'(package com.mycompany.emailaggregation;)

while on the other EPL I get:

the name mycompany in the com namespace does not exist(using com.mycompany.emailaggregation.EmailLine;)

The EPL will be injected once and there will be only one instance of the EmailAggregator.

Sorry about that error. Remove the “package …” and “using com.mycompany.emailaggregation.EmailLine” lines and see if it works.

The EPL will be injected once and there will be only one instance of the EmailAggregator.

So how would it work if you have multiple machines using EmailAggregator?
How can I filter that each machine has to send one email and not mix their text up between different machines?

You could add other variables to the EmailLine event and then group by this variable in the stream query.

event EmailLine {
	string text;
	string deviceId;
}
from emailLine in all EmailLine() within TIME_INTERVAL_SECONDS every TIME_INTERVAL_SECONDS
		  		group by emailLine.deviceId select createEmail(emailLine) as combinedEmail {

send EmailLine("Line1", "deviceA") to "my_email_channel";
Alternatively you could send messages relating to different devices to different channels.

send EmailLine("Line1") to "my_email_channel_A";

With, for example,

monitor EmailAggregator {

	constant float TIME_INTERVAL_SECONDS := 300.0; // 5 minutes
	
	action listenForLines(string emailLineChannel) {
		monitor.subscribe(emailLineChannel);
		
		from emailLine in all EmailLine() within TIME_INTERVAL_SECONDS every TIME_INTERVAL_SECONDS
		  		select createEmail(emailLine) as combinedEmail {
			send combinedEmail to SendEmail.SEND_CHANNEL;
		}
	}
	
	action onload {
		spawn listenForLines("my_email_channel_A") to context("Aggregator A");
		spawn listenForLines("my_email_channel_B") to context("Aggregator B");
	}
}

using com.mycompany.emailaggregation, gives me this error, do you know why?

the name mycompany in the com namespace does not exist(using com.mycompany.emailaggregation;)

The using statement is used to reference a package namespace declared elsewhere using a package statement.
The SendEmail event in the internal com.apama.cumulocity package is only visible to EPL files with the line
using com.apama.cumulocity.SendEmail;
To ensure the EmailLine event we defined was visible to your other EPL files, I decided to place it in a package and then reference this package in the other EPL. However the package keyword appears to be unsupported in Streaming Analytics so remove the package line and the associated “using com.mycompany.emailaggregation.EmailLine” line. I don’t think the lines are necessary.

According to a colleague, it is apparently not possible to define event types in one EPL app and use them in another in Streaming Analytics. (Apama is packaged into different products, each with their own limitations.) Unfortunately this means that communication must generally be done using the provided EPL event types like SendEmail (as in my first example) or all the code must be placed in the same EPL file.