I am sending mails from my application using JAVA mail on smtp server, port 465. My need is that, I have to set Message-ID before sending mail. I did some R&D and found the code below. I had override the method updateMessageID() of MimeMessage
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
public class CustomMimeMessage extends MimeMessage {
public CustomMimeMessage(Session session) {
super(session);
}
#Override
protected void updateMessageID() throws MessagingException {
setHeader("Message-ID", "message id");
}
}
And then I had made an instance of CustomMimeMessage in my service and then invoke updateMessageID() method using that instance, but I still get the Message-ID generated by gmail.
In your code
setHeader("Message-ID", "message id");
you are trying to set "message id" as Message-ID which is quite wrong you have to set a unique id that qualify all the rules of the message id (Read This).
Try this..,.
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class CustomMimeMessage extends MimeMessage {
Session session;
private static int id = 0;
public CustomMimeMessage(Session session) {
super(session);
this.session=session;
}
#Override
protected void updateMessageID() throws MessagingException {
setHeader("Message-ID", "<" + getUniqueMessageIDValue(session) + ">");
}
public static String getUniqueMessageIDValue(Session ssn) {
String suffix = null;
InternetAddress addr = InternetAddress.getLocalAddress(ssn);
if (addr != null)
suffix = addr.getAddress();
else {
suffix = "javamailuser#localhost"; // worst-case default
}
StringBuffer s = new StringBuffer();
// Unique string is <hashcode>.<id>.<currentTime>.JavaMail.<suffix>
s.append(s.hashCode()).append('.').append(getUniqueId()).append('.').
append(System.currentTimeMillis()).append('.').
append("JavaMail.").
append(suffix);
return s.toString();
}
private static synchronized int getUniqueId() {
return id++;
}
}
I am doing something similar but sending from the local host instead. This Might help.
import java.util.Properties;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.Transport;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
public class SendEmail {
/**
* Sends an email based on paramaters passed to it.
*
* #param toWho - the recipiants email address
* #param fromWho - the senders email address
* #param subject - the subject line of the email
* #param body - the email message body
* #return void
* #throws AddressException
* #throws MessageingException
*/
public void sendMail(String toWho, String subject, String body, String fromWho) throws AddressException, MessagingException {
// Setting Properties
Properties props = System.getProperties();
props.put("mail.imaps.ssl.trust", "*"); // trusting all server certificates
props.setProperty("mail.store.protocol", "imaps");
// Get the default Session object.
Session session = Session.getDefaultInstance(props, null);
// Create a default MimeMessage object.
MimeMessage message = new MimeMessage(session);
// Set From header
message.setFrom(new InternetAddress(fromWho));
// Set to header
message.addRecipient(Message.RecipientType.TO, new InternetAddress(toWho));
// Header set subject
message.setSubject(subject);
// Message Body
message.setContent(body, "text/html; charset=utf-8");
// Send message
Transport.send(message);
}
}
You can set message-id to MimeMessage before call Transport.send() by extending MimeMessage like this.
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
public class MyMimeMessage extends MimeMessage {
public MailorMimeMessage(Session session) {
super(session);
}
#Override
protected void updateMessageID() throws MessagingException {
if (getHeader("Message-Id") == null) {
super.updateMessageID();
}
}
}
And set custom message-id.
message.setHeader("Message-Id","<MY-MESSAGE-ID>");
You can try custom id with .(dot) before left side of '#'. It worked for me.
Check the following code snippet:
public class CustomMimeMessage extends MimeMessage {
Session session;
private static int id = 0;
public CustomMimeMessage(Session session) {
super(session);
this.session = session;
}
protected void updateMessageID() throws MessagingException {
debugLog("Calling updateMessageID()");
setHeader("Message-ID", "<" + getUniqueMessageIDValue(session) + ">");
}
public static String getUniqueMessageIDValue(Session ssn) {
String suffix = null;
InternetAddress addr = InternetAddress.getLocalAddress(ssn);
if (addr != null) {
testLog("InternetAddress = " + addr.toString());
String address = addr.getAddress();
if (address.contains("#")) {
address = address.substring(address.lastIndexOf("#"), address.length());
suffix = address;
}
}
if (suffix == null) {
suffix = "#mail";// worst-case default
}
testLog("suffix Address = " + suffix);
StringBuffer s = new StringBuffer();
s.append(System.currentTimeMillis()).append("")
.append(getUniqueId()).append(suffix).append(".sm");
testLog("NEW MESSAGE-ID: " + s.toString());
return s.toString();
}
private static synchronized int getUniqueId() {
return id++;
}
For more details, Please refer the following RFC's. These are really helpful for creating syntax for Custom message-id.
RFC 2822
RFC 5322
Hope this would also work for you.
Related
Following code sample found in:
https://www.codejava.net/java-ee/javamail/embedding-images-into-e-mail-with-javamail
The images are attached to the email, but not embedded in the html of the email.
package net.codejava.mail;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
/**
* This utility class provides a functionality to send an HTML e-mail message
* with embedded images.
* #author www.codejava.net
*
*/
public class EmbeddedImageEmailUtil {
/**
* Sends an HTML e-mail with inline images.
* #param host SMTP host
* #param port SMTP port
* #param userName e-mail address of the sender's account
* #param password password of the sender's account
* #param toAddress e-mail address of the recipient
* #param subject e-mail subject
* #param htmlBody e-mail content with HTML tags
* #param mapInlineImages
* key: Content-ID
* value: path of the image file
* #throws AddressException
* #throws MessagingException
*/
public static void send(String host, String port,
final String userName, final String password, String toAddress,
String subject, String htmlBody,
Map<String, String> mapInlineImages)
throws AddressException, MessagingException {
// sets SMTP server properties
Properties properties = new Properties();
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.port", port);
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.user", userName);
properties.put("mail.password", password);
// creates a new session with an authenticator
Authenticator auth = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
};
Session session = Session.getInstance(properties, auth);
// creates a new e-mail message
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(userName));
InternetAddress[] toAddresses = { new InternetAddress(toAddress) };
msg.setRecipients(Message.RecipientType.TO, toAddresses);
msg.setSubject(subject);
msg.setSentDate(new Date());
// creates message part
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(htmlBody, "text/html");
// creates multi-part
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// adds inline image attachments
if (mapInlineImages != null && mapInlineImages.size() > 0) {
Set<String> setImageID = mapInlineImages.keySet();
for (String contentId : setImageID) {
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.setHeader("Content-ID", "<" + contentId + ">");
imagePart.setDisposition(MimeBodyPart.INLINE);
String imageFilePath = mapInlineImages.get(contentId);
try {
imagePart.attachFile(imageFilePath);
} catch (IOException ex) {
ex.printStackTrace();
}
multipart.addBodyPart(imagePart);
}
}
msg.setContent(multipart);
Transport.send(msg);
}
}
package net.codejava.mail;
import java.util.HashMap;
import java.util.Map;
/**
* This program tests out the EmbeddedImageEmailUtil utility class.
* #author www.codejava.net
*
*/
public class InlineImageEmailTester {
/**
* main entry of the program
*/
public static void main(String[] args) {
// SMTP info
String host = "smtp.gmail.com";
String port = "587";
String mailFrom = "YOUR_EMAIL";
String password = "YOUR_PASSWORD";
// message info
String mailTo = "YOUR_RECIPIENT";
String subject = "Test e-mail with inline images";
StringBuffer body
= new StringBuffer("<html>This message contains two inline images.<br>");
body.append("The first image is a chart:<br>");
body.append("<img src=\"cid:image1\" width=\"30%\" height=\"30%\" /><br>");
body.append("The second one is a cube:<br>");
body.append("<img src=\"cid:image2\" width=\"15%\" height=\"15%\" /><br>");
body.append("End of message.");
body.append("</html>");
// inline images
Map<String, String> inlineImages = new HashMap<String, String>();
inlineImages.put("image1", "E:/Test/chart.png");
inlineImages.put("image2", "E:/Test/cube.jpg");
try {
EmbeddedImageEmailUtil.send(host, port, mailFrom, password, mailTo,
subject, body.toString(), inlineImages);
System.out.println("Email sent.");
} catch (Exception ex) {
System.out.println("Could not send email.");
ex.printStackTrace();
}
}
}
Any comments will be very appreciated.
Problem solved.
I have to change:
new MimeMultipart();
to this:
new MimeMultipart("related");
I have a MailDev instance installed on a remote Server.
I'm trying to understand if is it possibile to send email with Java (using the standard JavaMailSender) using this fake SMTP server.
The config needs only the URL and the port but, in my case, it doesn't work.
It returns always:
Mail server connection failed; nested exception is com.sun.mail.util.MailConnectException: Couldn't connect to host ...
The WebUI is running correctly and I can see the empty inbox on server.
Thanks.
It seems like you are experience connections issues. Although I cannot tell you what the cause there is, perhaps I can offer an alternative solution to test your emails?
Using Wiser, you can run an embedded SMTP server and query that inside your junit test. I've used this a lot in my open source project Simple Java Mail and created a Rule for this:
package testutil.testrules;
import org.jetbrains.annotations.NotNull;
import org.junit.rules.ExternalResource;
import org.subethamail.smtp.server.SMTPServer;
import org.subethamail.wiser.Wiser;
import org.subethamail.wiser.WiserMessage;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.List;
/**
* SmtpServerRule - a TestRule wrapping a Wiser instance (a SMTP server in Java), started and stopped right before and after each test.
* <br>
* SmtpServerRule exposes the same methods as the {#link Wiser} instance by delegating the implementation to the instance. These methods, however, can not be
* used outside a JUnit statement (otherwise an {#link IllegalStateException} is raised).
* <br>
* The {#link Wiser} instance can be directly retrieved but also only from inside a JUnit statement.
*/
public class SmtpServerRule extends ExternalResource {
private final Wiser wiser = new Wiser();
private final int port;
public SmtpServerRule(#NotNull Integer port) {
this.port = port;
}
#Override
protected void before() {
this.wiser.setPort(port);
this.wiser.start();
}
#Override
protected void after() {
this.wiser.stop();
}
#NotNull
public Wiser getWiser() {
checkState("getWiser()");
return this.wiser;
}
#NotNull
public List<WiserMessage> getMessages() {
checkState("getMessages()");
return wiser.getMessages();
}
#NotNull
public MimeMessage getOnlyMessage(String envelopeReceiver)
throws MessagingException {
checkState("getMessages()");
List<WiserMessage> messages = getMessages();
assertThat(messages).hasSize(1);
Iterator<WiserMessage> iterator = messages.iterator();
WiserMessage wiserMessage = iterator.next();
assertThat(wiserMessage.getEnvelopeReceiver()).isEqualTo(envelopeReceiver);
MimeMessage mimeMessage = wiserMessage.getMimeMessage();
iterator.remove();
return mimeMessage;
}
#NotNull
public MimeMessageAndEnvelope getOnlyMessage()
throws MessagingException {
checkState("getMessages()");
List<WiserMessage> messages = getMessages();
assertThat(messages).hasSize(1);
Iterator<WiserMessage> iterator = messages.iterator();
WiserMessage wiserMessage = iterator.next();
iterator.remove();
return new MimeMessageAndEnvelope(wiserMessage.getMimeMessage(), wiserMessage.getEnvelopeSender());
}
#NotNull
public MimeMessage getMessage(String envelopeReceiver)
throws MessagingException {
checkState("getMessages()");
List<WiserMessage> messages = getMessages();
Iterator<WiserMessage> iterator = messages.iterator();
while (iterator.hasNext()) {
WiserMessage wiserMessage = iterator.next();
if (wiserMessage.getEnvelopeReceiver().equals(envelopeReceiver)) {
MimeMessage mimeMessage = wiserMessage.getMimeMessage();
iterator.remove();
return mimeMessage;
}
}
throw new AssertionError("message not found for recipient " + envelopeReceiver);
}
#NotNull
public SMTPServer getServer() {
checkState("getServer()");
return wiser.getServer();
}
public boolean accept(String from, String recipient) {
checkState("accept(String, String)");
return wiser.accept(from, recipient);
}
public void deliver(String from, String recipient, InputStream data)
throws IOException {
checkState("deliver(String, String, InputStream)");
wiser.deliver(from, recipient, data);
}
public void dumpMessages(PrintStream out)
throws MessagingException {
checkState("dumpMessages(PrintStream)");
wiser.dumpMessages(out);
}
private void checkState(String method) {
if (this.wiser == null) {
throw new IllegalStateException(format("%s must not be called outside of a JUnit statement", method));
}
}
}
Then I use it like this:
public class MailerLiveTest {
private static final Integer SERVER_PORT = 251;
#Rule
public final SmtpServerRule smtpServerRule = new SmtpServerRule(SERVER_PORT);
#Before
public void setup() {
mailer = MailerBuilder.withSMTPServer("localhost", SERVER_PORT).buildMailer();
}
#Test
public void createMailSession_EmptySubjectAndBody() {
// send mail using mailer, which goes to localhost:251
MimeMessageAndEnvelope receivedMimeMessage = smtpServerRule.getOnlyMessage();
Email receivedEmail = EmailConverter.mimeMessageToEmail(receivedMimeMessage.getMimeMessage());
// perform assertions on Email object...
}
}
Check if mail.smtp.auth and mail.smtp.starttls.enable are set to false. In my case it worked (I also set localhost as host and 1025 as port).
I created a method to send email in VB.NET:
Imports System.Threading
Imports System.Net.Mail
Imports System.ComponentModel
Module Module1
Dim smtpList As New ArrayList
Dim counter = 0
Private Sub smtpClient_SendCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
System.Diagnostics.Debug.WriteLine("completed!")
System.Console.WriteLine("completed!")
End Sub
Public Function createSmtp() As SmtpClient
Dim smtp = New SmtpClient()
Dim user = "AKAKAKAKAKAKAKAK"
Dim host = "smtp.mailgun.org"
Dim pass = "akakakakakakakakakakakakakakakakakakakak"
smtp.Host = host
smtp.Port = 587
smtp.Credentials = New System.Net.NetworkCredential(user, pass)
smtp.EnableSsl = True
Return smtp
End Function
Public Sub SendEmail(email As String, bodystuff As String, smtp As SmtpClient)
Dim from As New MailAddress("contat#testsitetetete.com", "Info", System.Text.Encoding.UTF8)
Dim [to] As New MailAddress(email)
Dim message As New MailMessage(from, [to])
message.Body = String.Format("The message I want to send is to this <b>contact: {0}{1}</b>", vbCrLf, bodystuff)
message.IsBodyHtml = True
message.BodyEncoding = System.Text.Encoding.UTF8
message.Subject = "Test email subject"
message.SubjectEncoding = System.Text.Encoding.UTF8
message.Priority = MailPriority.High
' Set the method that is called back when the send operation ends.
AddHandler smtp.SendCompleted, AddressOf smtpClient_SendCompleted
smtp.Send(message)
'smtp.SendMailAsync(message)
counter = counter + 1 ' I know its not thread safe, just to get a counter
System.Console.WriteLine("Counter -> " & counter)
End Sub
Public Sub StartEmailRun()
System.Diagnostics.Debug.WriteLine("StartEmailRun")
'Dim smtp = createSmtp()
Try
For i = 0 To 8
Dim thread As New Thread(
Sub()
Dim smtp = createSmtp()
SendEmail("someamail#testemail.com", "email test", createSmtp())
End Sub
)
thread.Start()
Next
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Sub Main()
System.Diagnostics.Debug.WriteLine("Starting the email sending...")
ThreadPool.SetMinThreads(100, 100) ' just to make sure no thread pool issue or limitation
createSmtp()
StartEmailRun()
Thread.Sleep(300000) ' make the program alive
End Sub
End Module
and I created this same method in java:
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
public class TestMail
{
public static void main(String[] args) throws AddressException, MessagingException, InterruptedException
{
Properties prop = new Properties();
prop.put("mail.smtp.auth", true);
prop.put("mail.smtp.starttls.enable", "true");
prop.put("mail.smtp.host", "smtp.mailgun.org");
prop.put("mail.smtp.port", "587");
prop.put("mail.smtp.ssl.trust", "smtp.mailgun.org");
Session session = Session.getInstance(prop, new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
String username = "akakakakakakakakakak";
String password = "kajdfkjasfkjasdfksjdfksdajfksdfjsdkfjdskfjkW";
return new PasswordAuthentication(username, password);
}
});
final Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("testacount#test.com"));
message.setRecipients(
Message.RecipientType.TO, InternetAddress.parse("atest#test.com"));
message.setSubject("Mail Subject");
String msg = "This is my first email using JavaMailer";
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setContent(msg, "text/html");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(mimeBodyPart);
message.setContent(multipart);
for (int i = 0; i < 8; i++)
{
new Thread(new Runnable() {
public void run() {
try {
Transport.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
System.out.println("sent...");
}
}).start();
}
while(true)
{
Thread.sleep(1000);
}
}
}
I expected the VB.NET code to sent the emails simultanteously, like the java one does.
But the email sent appears to be sequencial. In the java all the emails are sent simultaneosly.
I think there is some limitation on send multiple emails in the VB.Net code.
Is there a way to send multiple emails at the same time in VB.NET???
p.s. not talking about bbc, because every email is different from another.
I'm not able to find a way to read messages from pub/sub using java.
I'm using this maven dependency in my pom
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-pubsub</artifactId>
<version>0.17.2-alpha</version>
</dependency>
I implemented this main method to create a new topic:
public static void main(String... args) throws Exception {
// Your Google Cloud Platform project ID
String projectId = ServiceOptions.getDefaultProjectId();
// Your topic ID
String topicId = "my-new-topic-1";
// Create a new topic
TopicName topic = TopicName.create(projectId, topicId);
try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) {
topicAdminClient.createTopic(topic);
}
}
The above code works well and, indeed, I can see the new topic I created using the google cloud console.
I implemented the following main method to write a message to my topic:
public static void main(String a[]) throws InterruptedException, ExecutionException{
String projectId = ServiceOptions.getDefaultProjectId();
String topicId = "my-new-topic-1";
String payload = "Hellooooo!!!";
PubsubMessage pubsubMessage =
PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8(payload)).build();
TopicName topic = TopicName.create(projectId, topicId);
Publisher publisher;
try {
publisher = Publisher.defaultBuilder(
topic)
.build();
publisher.publish(pubsubMessage);
System.out.println("Sent!");
} catch (IOException e) {
System.out.println("Not Sended!");
e.printStackTrace();
}
}
Now I'm not able to verify if this message was really sent.
I would like to implement a message reader using a subscription to my topic.
Could someone show me a correct and working java example about reading messages from a topic?
Anyone can help me?
Thanks in advance!
Here is the version using the google cloud client libraries.
package com.techm.data.client;
import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.ProjectTopicName;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.PushConfig;
/**
* A snippet for Google Cloud Pub/Sub showing how to create a Pub/Sub pull
* subscription and asynchronously pull messages from it.
*/
public class CreateSubscriptionAndConsumeMessages {
private static String projectId = "projectId";
private static String topicId = "topicName";
private static String subscriptionId = "subscriptionName";
public static void createSubscription() throws Exception {
ProjectTopicName topic = ProjectTopicName.of(projectId, topicId);
ProjectSubscriptionName subscription = ProjectSubscriptionName.of(projectId, subscriptionId);
try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {
subscriptionAdminClient.createSubscription(subscription, topic, PushConfig.getDefaultInstance(), 0);
}
}
public static void main(String... args) throws Exception {
ProjectSubscriptionName subscription = ProjectSubscriptionName.of(projectId, subscriptionId);
createSubscription();
MessageReceiver receiver = new MessageReceiver() {
#Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
System.out.println("Received message: " + message.getData().toStringUtf8());
consumer.ack();
}
};
Subscriber subscriber = null;
try {
subscriber = Subscriber.newBuilder(subscription, receiver).build();
subscriber.addListener(new Subscriber.Listener() {
#Override
public void failed(Subscriber.State from, Throwable failure) {
// Handle failure. This is called when the Subscriber encountered a fatal error
// and is
// shutting down.
System.err.println(failure);
}
}, MoreExecutors.directExecutor());
subscriber.startAsync().awaitRunning();
// In this example, we will pull messages for one minute (60,000ms) then stop.
// In a real application, this sleep-then-stop is not necessary.
// Simply call stopAsync().awaitTerminated() when the server is shutting down,
// etc.
Thread.sleep(60000);
} finally {
if (subscriber != null) {
subscriber.stopAsync().awaitTerminated();
}
}
}
}
This is working fine for me.
The Cloud Pub/Sub Pull Subscriber Guide has sample code for reading messages from a topic.
I haven't used google cloud client libraries but used the api client libraries. Here is how I created a subscription.
package com.techm.datapipeline.client;
import java.io.IOException;
import java.security.GeneralSecurityException;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpStatusCodes;
import com.google.api.services.pubsub.Pubsub;
import com.google.api.services.pubsub.Pubsub.Projects.Subscriptions.Create;
import com.google.api.services.pubsub.Pubsub.Projects.Subscriptions.Get;
import com.google.api.services.pubsub.Pubsub.Projects.Topics;
import com.google.api.services.pubsub.model.ExpirationPolicy;
import com.google.api.services.pubsub.model.Subscription;
import com.google.api.services.pubsub.model.Topic;
import com.techm.datapipeline.factory.PubsubFactory;
public class CreatePullSubscriberClient {
private final static String PROJECT_NAME = "yourProjectId";
private final static String TOPIC_NAME = "yourTopicName";
private final static String SUBSCRIPTION_NAME = "yourSubscriptionName";
public static void main(String[] args) throws IOException, GeneralSecurityException {
Pubsub pubSub = PubsubFactory.getService();
String topicName = String.format("projects/%s/topics/%s", PROJECT_NAME, TOPIC_NAME);
String subscriptionName = String.format("projects/%s/subscriptions/%s", PROJECT_NAME, SUBSCRIPTION_NAME);
Topics.Get listReq = pubSub.projects().topics().get(topicName);
Topic topic = listReq.execute();
if (topic == null) {
System.err.println("Topic doesn't exist...run CreateTopicClient...to create the topic");
System.exit(0);
}
Subscription subscription = null;
try {
Get getReq = pubSub.projects().subscriptions().get(subscriptionName);
subscription = getReq.execute();
} catch (GoogleJsonResponseException e) {
if (e.getStatusCode() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) {
System.out.println("Subscription " + subscriptionName + " does not exist...will create it");
}
}
if (subscription != null) {
System.out.println("Subscription already exists ==> " + subscription.toPrettyString());
System.exit(0);
}
subscription = new Subscription();
subscription.setTopic(topicName);
subscription.setPushConfig(null); // indicating a pull
ExpirationPolicy expirationPolicy = new ExpirationPolicy();
expirationPolicy.setTtl(null); // never expires;
subscription.setExpirationPolicy(expirationPolicy);
subscription.setAckDeadlineSeconds(null); // so defaults to 10 sec
subscription.setRetainAckedMessages(true);
Long _week = 7L * 24 * 60 * 60;
subscription.setMessageRetentionDuration(String.valueOf(_week)+"s");
subscription.setName(subscriptionName);
Create createReq = pubSub.projects().subscriptions().create(subscriptionName, subscription);
Subscription createdSubscription = createReq.execute();
System.out.println("Subscription created ==> " + createdSubscription.toPrettyString());
}
}
And once you create the subscription (pull type)...this is how you pull the messages from the topic.
package com.techm.datapipeline.client;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpStatusCodes;
import com.google.api.client.util.Base64;
import com.google.api.services.pubsub.Pubsub;
import com.google.api.services.pubsub.Pubsub.Projects.Subscriptions.Acknowledge;
import com.google.api.services.pubsub.Pubsub.Projects.Subscriptions.Get;
import com.google.api.services.pubsub.Pubsub.Projects.Subscriptions.Pull;
import com.google.api.services.pubsub.model.AcknowledgeRequest;
import com.google.api.services.pubsub.model.Empty;
import com.google.api.services.pubsub.model.PullRequest;
import com.google.api.services.pubsub.model.PullResponse;
import com.google.api.services.pubsub.model.ReceivedMessage;
import com.techm.datapipeline.factory.PubsubFactory;
public class PullSubscriptionsClient {
private final static String PROJECT_NAME = "yourProjectId";
private final static String SUBSCRIPTION_NAME = "yourSubscriptionName";
private final static String SUBSCRIPTION_NYC_NAME = "test";
public static void main(String[] args) throws IOException, GeneralSecurityException {
Pubsub pubSub = PubsubFactory.getService();
String subscriptionName = String.format("projects/%s/subscriptions/%s", PROJECT_NAME, SUBSCRIPTION_NAME);
//String subscriptionName = String.format("projects/%s/subscriptions/%s", PROJECT_NAME, SUBSCRIPTION_NYC_NAME);
try {
Get getReq = pubSub.projects().subscriptions().get(subscriptionName);
getReq.execute();
} catch (GoogleJsonResponseException e) {
if (e.getStatusCode() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) {
System.out.println("Subscription " + subscriptionName
+ " does not exist...run CreatePullSubscriberClient to create");
}
}
PullRequest pullRequest = new PullRequest();
pullRequest.setReturnImmediately(false); // wait until you get a message
pullRequest.setMaxMessages(1000);
Pull pullReq = pubSub.projects().subscriptions().pull(subscriptionName, pullRequest);
PullResponse pullResponse = pullReq.execute();
List<ReceivedMessage> msgs = pullResponse.getReceivedMessages();
List<String> ackIds = new ArrayList<String>();
int i = 0;
if (msgs != null) {
for (ReceivedMessage msg : msgs) {
ackIds.add(msg.getAckId());
//System.out.println(i++ + ":===:" + msg.getAckId());
String object = new String(Base64.decodeBase64(msg.getMessage().getData()));
System.out.println("Decoded object String ==> " + object );
}
//acknowledge all the received messages
AcknowledgeRequest content = new AcknowledgeRequest();
content.setAckIds(ackIds);
Acknowledge ackReq = pubSub.projects().subscriptions().acknowledge(subscriptionName, content);
Empty empty = ackReq.execute();
}
}
}
Note: This client only waits until it receives at least one message and terminates if it's receives one (up to a max of value - set in MaxMessages) at once.
Let me know if this helps. I'm going to try the cloud client libraries soon and will post an update once I get my hands on them.
And here's the missing factory class ...if you plan to run it...
package com.techm.datapipeline.factory;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.pubsub.Pubsub;
import com.google.api.services.pubsub.PubsubScopes;
public class PubsubFactory {
private static Pubsub instance = null;
private static final Logger logger = Logger.getLogger(PubsubFactory.class.getName());
public static synchronized Pubsub getService() throws IOException, GeneralSecurityException {
if (instance == null) {
instance = buildService();
}
return instance;
}
private static Pubsub buildService() throws IOException, GeneralSecurityException {
logger.log(Level.FINER, "Start of buildService");
HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory);
// Depending on the environment that provides the default credentials (for
// example: Compute Engine, App Engine), the credentials may require us to
// specify the scopes we need explicitly.
if (credential.createScopedRequired()) {
Collection<String> scopes = new ArrayList<>();
scopes.add(PubsubScopes.PUBSUB);
credential = credential.createScoped(scopes);
}
logger.log(Level.FINER, "End of buildService");
// TODO - Get the application name from outside.
return new Pubsub.Builder(transport, jsonFactory, credential).setApplicationName("Your Application Name/Version")
.build();
}
}
The message reader is injected on the subscriber. This part of the code will handle the messages:
MessageReceiver receiver =
new MessageReceiver() {
#Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
// handle incoming message, then ack/nack the received message
System.out.println("Id : " + message.getMessageId());
System.out.println("Data : " + message.getData().toStringUtf8());
consumer.ack();
}
};
Error 1:
Description Resource Path Location Type The project was not built
since its build path is incomplete. Cannot find the class file for
java.util.Map$Entry. Fix the build path then try building this project
EmailSendingWebApp Unknown Java Problem
error 2 :
Description Resource Path Location Type The type java.util.Map$Entry
cannot be resolved. It is indirectly referenced from required .class
files EmailUtility.java /EmailSendingWebApp/src/net/codejava/email
line 29 Java Problem
This is my code:
code 1 : package net.codejava.email;
import java.util.Date;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
* A utility class for sending e-mail messages
* #author www.codejava.net
*
*/
public class EmailUtility {
public static void sendEmail(String host, String port,
final String userName, final String password, String toAddress,
String subject, String message) throws AddressException,
MessagingException {
// sets SMTP server properties
Properties properties = new Properties();
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.port", port);
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
// creates a new session with an authenticator
Authenticator auth = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
};
Session session = Session.getInstance(properties, auth);
// creates a new e-mail message
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(userName));
InternetAddress[] toAddresses = { new InternetAddress(toAddress) };
msg.setRecipients(Message.RecipientType.TO, toAddresses);
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setText(message);
// sends the e-mail
Transport.send(msg);
}
}
code 2 :
package net.codejava.email;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A servlet that takes message details from user and send it as a new e-mail
* through an SMTP server.
*
* #author www.codejava.net
*
*/
#WebServlet("/EmailSendingServlet")
public class EmailSendingServlet extends HttpServlet {
private String host;
private String port;
private String user;
private String pass;
public void init() {
// reads SMTP server setting from web.xml file
ServletContext context = getServletContext();
host = context.getInitParameter("host");
port = context.getInitParameter("port");
user = context.getInitParameter("user");
pass = context.getInitParameter("pass");
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// reads form fields
String recipient = request.getParameter("recipient");
String subject = request.getParameter("subject");
String content = request.getParameter("content");
String resultMessage = "";
try {
EmailUtility.sendEmail(host, port, user, pass, recipient, subject,
content);
resultMessage = "The e-mail was sent successfully";
} catch (Exception ex) {
ex.printStackTrace();
resultMessage = "There were an error: " + ex.getMessage();
} finally {
request.setAttribute("Message", resultMessage);
getServletContext().getRequestDispatcher("/Result.jsp").forward(
request, response);
}
}
}
I am new to eclipse so I don't know how to link these two files, please help. Thanks.
Eclipse can compile Java projects against different installed JREs. Unless care is taken, the project's reference to its JRE is not portable. Verify that your Installed JREs preference page is pointing to something valid, then edit the project's Java Build Path so that it's referring to a valid JRE.
http://help.eclipse.org/neon/topic/org.eclipse.jdt.doc.user/reference/preferences/java/debug/ref-installed_jres.htm
http://help.eclipse.org/neon/topic/org.eclipse.jdt.doc.user/reference/ref-properties-build-path.htm?cp=1_4_3_1