I am coding POP3 and SMTP servers using Java for an university project.
I can send emails using my SMTP server via a client (ie: Thunderbird) and my server sends them without any problem.
When an external sender agent, like gmail or hotmail, tries to send an email using my SMTP server, it does not complete the communication because it sends the QUIT command after the MAIL command. Why the external agent does that? Didn't I obey to the SMTP protocol?
The problem is that when I receive a connection from the an external server that wants to send me mail the following happens (me: my SMTP server, sender: sender agent). Here is an example with a gmail agent.
sender: establishes a connection
me: 220 Welcome
sender: HELO agent id
me: 250 Fine
sender: MAIL FROM:<address#gmail.com>
me (after address verification): 250
sender: QUIT
me: 221
Relevant code snippets (full class code is at http://code.google.com/p/sd-mail-server-claudiani-ferrari/source/browse/src/controller/smtp/SMTPCommandHandler.java?repo=mailserver )
private void MAILCommand(CommunicationHandler communicationHandler,
BufferedOutputStream writer,
PersistanceManager persistanceManager,
String clientId,
String argument)
{
String address = getAddressFromArgument(argument);
if (!isValidAddress(address, persistanceManager)) {
communicationHandler.sendResponse(writer,
SMTPCode.SYNTAX_ERROR.toString(),
"Address is not valid.");
return;
}
// Initialize data
persistanceManager.create(StorageLocation.SMTP_TEMP_MESSAGE_STORE,
FieldName.getSMTPTempTableFromFieldOnly(),
clientId, address);
communicationHandler.sendResponse(writer, SMTPCode.OK.toString(), "");
}
private void RCPTCommand(CommunicationHandler communicationHandler,
BufferedOutputStream writer,
PersistanceManager persistanceManager,
String clientId,
String argument)
{
String address = getAddressFromArgument(argument);
// Check the address
if (!isValidAddress(address, persistanceManager)) {
communicationHandler.sendResponse(writer,
SMTPCode.SYNTAX_ERROR.toString(),
"Address is not valid.");
return;
}
persistanceManager.addToSet(StorageLocation.SMTP_TEMP_MESSAGE_STORE,
clientId,
FieldName.SMTP_TEMP_TO_ADDRESSES,
address);
communicationHandler.sendResponse(writer, SMTPCode.OK.toString(), "");
}
private void DATACommand(CommunicationHandler communicationHandler,
BufferedOutputStream writer,
PersistanceManager persistanceManager,
String clientId)
{
communicationHandler.sendResponse(writer,
SMTPCode.INTERMEDIATE_REPLY.toString(),
"Start mail input; end with [CRLF].[CRLF]");
}
Have you tried replying with 250 OK instead of just 250 ? RFC 2821 says that this should be the reply of a MAIL FROM line:
If accepted, the SMTP server returns
a 250 OK reply. If the mailbox specification is not acceptable for
some reason, the server MUST return a reply indicating whether the
Your mail client might be satisfied with seeing 250, while Google/Hotmail might expect 250 OK.
Edit
I think the text string isn't optional in this case, see section 4.2 of RFC 2821:
An SMTP reply consists of a three digit number (transmitted as
three numeric characters) followed by some text unless specified
otherwise in this document.
The current RFC 5321 suggests that clients should accept no text:
An SMTP client MUST determine its actions only by the reply code,
not by the text (except for the "change of address" 251 and 551
and, if necessary, 220, 221, and 421 replies); in the general case,
any text, including no text at all (although senders SHOULD NOT
send bare codes), MUST be acceptable. The space (blank) following
the reply code is considered part of the text. Whenever possible,
a receiver- SMTP SHOULD test the first digit (severity indication)
of the reply code.
Related
I'm a novice in Java socket communication, I'm trying to connect 3 clients to a server without the use of threads as the number of clients connected to the server will as be 3. I have written a condition in the server to tokenize the received input from the client and send write to the respective stream. But the message isn't reaching the server so I'm not sure whether the client isn't writing to the stream or the server is unable to receive the data. I'm trying to establish a cryptographic protocol between the connected clients for demonstration purposes.
I was using BufferedReader and PrintStream earlier since I was testing with keyboard input, then I changed to data streams still doesn't seem to work
Here my code at Server.java to forward messages, the control doesn't appear to come to this loop at all(not sure).
while(true){
String recvd=cin2.readLine();
System.out.println("At server: "+recvd);
StringTokenizer st = new StringTokenizer(recvd);
String MsgToSend=st.nextToken();
String recipient=st.nextToken();
if(recipient.equalsIgnoreCase("client1")){
cout2.writeUTF(MsgToSend);
}
else if(recipient.equalsIgnoreCase("client2")){
cout.writeUTF(MsgToSend);
}
else if(recipient.equalsIgnoreCase("client3")){
cout3.writeUTF(MsgToSend);
}
}
Here is my client-side code,
while(i==0){
String s1="A";
String s2="B";
String s3="client1";
String toSend=String.join(" ",s1+s2,s3);
System.out.println("toSend :"+toSend);
sout.writeUTF(toSend);
sout.flush();
i++;
}
Receiving Client,
while (true){
s=sin.readLine();
System.out.print("Server : "+s+"\n");
}
Not sure whether the client is unable to write or the server is unable to read. Any suggestions or solutions to correct the code?
The socket navigation logic in your server file seems to be strange as you are manually creating a string with keyword client1 and then tokenizing it for navigation. By this approach your flow would get static and establishment of a protocol gets difficult.
Please see:
You are sending the data to client 1 by forming the string AB client1, then your server file's first line is using client 2 socket reading. (Sending data from client1 socket to client1 socket, not right).
Please change that to client1 socket reading, use prinln() and readline() to send and read socket data and then check if your flow is fine!
Also, for the protocol flow, you have to send the data to the other two sockets and not to the one that is sending.
For eg: if you are sending the data from client 1 to client 2, as per your approach, you have to for a string AB client2 and send to the server, tokenize it and navigate the flow to client 2.
Hope this helps!
Thanks,
Areed
I am working with SMTP server and found out an issue.
1) SMTP server is not down: In this case, the SMTP server is busy servicing email requests concurrently and continuously for more than 5 minutes (I'm sending bulk mails). At some point of time during servicing, it is not returning or throwing any exceptions to the Java/JavaMail program. In fact, I've experienced this kind of situation in my real time. In case, if I've not set both mail.smtp.timeout and mail.smtp.connectiontimeout properties within my code, it would never return and goes into infinite state.
If i do set my mail.smtp.connectiontimeout and mail.smtp.timeout, how can I test it?
How can we simulate/reproduce this kind of situation? Any ideas?
2) Also another issue is caused by networking issue where I send the request to SMTP form my java code, and it is queued. I am not sure what happens (I dont have a java loop) but the SMTP sends out multiple emails to the same person. Is it because the SMTP did not send back an response? Should the code not timeout after 3000?
Below is my code
props.put("mail.smtp.timeout", 3000);
props.put("mail.smtp.connectiontimeout", 3000);
SMTPTransport transport = (SMTPTransport)session.getTransport("smtp");
/ do some message setting here /
transport.connect();
int SMTPCodeBeforeSendingMessage = transport.getLastReturnCode();
logger.debug("Connection Code for SMTP connection after connect before sending mesasge" + SMTPCodeBeforeSendingMessage);
transport.sendMessage(msg, msg.getAllRecipients());
String SMTPresponse = transport.getLastServerResponse();
logger.debug("SMTP resposne after sending message" + SMTPresponse);
transport.close();
We tried to send mail using javax.mail. While sending mails we got following exception:
**sendMail - Message Sending Failed: Invalid Addresses;
nested exception is:
javax.mail.SendFailedException: 550 #5.1.0 Address rejected.2013-02-28 13:17:08,236**
What might be the problem?
It means that the receiving server does not recognise the mailbox (the part before the '#') of the e-mail address. It could be that it was misspelled, that it is simply a non-existing name, or it could even be that the receiving server was set to reject a message (e.g. spam) by replying with code 550.
Here is one of many pages that summarises the SMTP reply codes, and gives links to various relevant RFCs: http://www.greenend.org.uk/rjk/tech/smtpreplies.html.
EDIT: I need a bit more space to answer your question than the comments allow.
#RaghuKing, if you look at the Javadoc for javax.mail.SendFailedException, you will notice that you can call 3 methods on such an exception object (inside the catch block):
getInvalidAddresses() to get an array of addresses that are invalid and thus not sent to,
getValidSentAddresses() to get an array of addresses to which this message was sent succesfully, and
getValidUnsentAddresses() to get an array of addresses that are valid but to which the message was not sent to.
(Obviously, if one sends a message to multiple recipients, some may succeed and some fail, but the exception is thrown if there is at least one failure, regardless of how many successes. Obviously also if you are sending to only one address, you will have that one address in only one of these arrays, and it will probably NOT be in the ValidSent list.
These arrays will give you more information how to handle the exception, depending of the type of array an address is in. This will obviously depend on you application, but these might be reasonable suggestions:
Invalid Addresses: tell the user that the message was not sent because the address was wrong, for each invalid address in the list, and provide a way to correct the address, then try to resend to the correct address (or cancel if the user does not provide a different address);
Valid Sent Addresses: Don't resend;
Valid Unsent Addresses: Try to resend to these addresses. Sending probably stopped before getting to these addresses because of a previous incorrect address.
But in the end it is you who has to apply common sense, and perhaps experiment a little with the functions you don't understand until you understand them.
This code can print logs for invalid address(es):
try {
sender.send(message);
}catch (MailSendException me){
detectInvalidAddress(me);
}
private void detectInvalidAddress(MailSendException me) {
Exception[] messageExceptions = me.getMessageExceptions();
if (messageExceptions.length > 0) {
Exception messageException = messageExceptions[0];
if (messageException instanceof SendFailedException) {
SendFailedException sfe = (SendFailedException) messageException;
Address[] invalidAddresses = sfe.getInvalidAddresses();
StringBuilder addressStr = new StringBuilder();
for (Address address : invalidAddresses) {
addressStr.append(address.toString()).append("; ");
}
logger.error("invalid address(es):{}", addressStr);
return;
}
}
logger.error("exception while sending mail.", me);
}
Had experienced this same exception .I realized that i could not send email to unknown users . After consulting , i found out that our SMTP server was not an open mail relay server read Open mail Relay.
Good day guys!. I'm having a problem trying to submit an international sms vía SMPP (using Logica Java library). I'm gonna summarize the tests I've done. I'm using WireShark to monitor SMPP related activities.
(Working)
//Connect and stablish session
Connection conn = new TCPIPConnection(providerAddress, port);
Session session = new Session(conn);
BindRequest breq = new BindTransmitter();
breq.setSystemId(user);
breq.setPassword(pass);
breq.setSystemType("CMT");
breq.setInterfaceVersion((byte)34);
breq.setAddressRange((byte)0x01, (byte)0x01,null);
Response resp = session.bind(breq);
//Create message
SubmitSM msg = new SubmitSM();
msg.setDestAddr((byte)1, (byte)1, "58412014XXXX");
msg.setSourceAddr((byte)1, (byte)1, "58412014XXXX");
msg.setShortMessage("Test from tedexis","ISO-8859-1");
//Here we submit message
session.submit(msg);
//Disconnect
session.unbind();
Result: Message is delivered correctly. Here we validate credentials are valid, and notice the source and destination addresses are the same
(Failing) The code remains the same except for the message destination address which is now set for an INTERNATIONAL PHONE NUMBER
msg.setSourceAddr((byte)1, (byte)1, "1321237XXXX");
Result: Fails, checking WireShark I observe the following exception during the submit:
SMPP Submit_sm - resp: "Invalid destination address"
We may think that our credentials are not valid for international deliveries but we are currently using these credentials delivering international messages through their webservice interface.
I must be missing a configuration setting or wrongly setting one already, but I ran out of ideas, if anyone can point me in the right direction I would be glad.
First, you dont have to set your address range since you're binding as a transmitter, because the address range is used to inform the SMSC that this 'receiver' session will handle MO messages from the desired address range.
As for sending to international numbers, i'm not into logica's API but i'm pretty sure that you're missing to set the destination address ton to 1 (international number) and the destination address npi to 0 (Unknown) or 1 (ISDN) and retry the sending.
If the error persists, you'll have to call your provider, it is possible that they gave you the permission to send to international numbers through webservice only.
When I send out an e-mail and it isn't received, how can I figure out what the cause of the problem is?
My app sends e-mails through SMTP using the Apache commons-mail library. For testing purposes, I am using the gmail SMTP server. (Our production app uses an internal server on our network).
In one case on the test server, I have a batch job that generates 5 e-mails with attachments. Some e-mails are received and others are marked as sent, but never appear in my inbox. There doesn't seem to be a pattern to which e-mails are received and which ones silently vanish.
The code that sends and checks for errors looks like this:
final Mail mail = ...;
//The Mail class is our app's mail object, which provides data used to generate the MIME e-mail and record the results.
final MultiPartEmail email = ...;
try {
email.setSentDate(mail.getDateSent());
email.send();
}
catch (EmailException ee) {
success = false;
mail.setDateSent(null);
getLog().error("Mail not sent: ", ee);
if (ee.getMessage().indexOf("receiver address required") != -1) {
mail.setErrorMessage(ee.getMessage());
getLog().error(mail.toString());
}
}
In the debugger, I determine that no exception is thrown.
My first guess was that the attachment size is too large; but, gmail supposedly supports 25MB attachments, and my largest attachment is 14.3 MB. In some cases when I run the entire batch of 5 e-mails, the e-mail with the largest attachment gets through, and the smaller ones disappear.