001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.net.smtp; 019 020 import java.io.IOException; 021 import java.io.Writer; 022 import java.net.InetAddress; 023 024 import org.apache.commons.net.io.DotTerminatedMessageWriter; 025 026 /*** 027 * SMTPClient encapsulates all the functionality necessary to send files 028 * through an SMTP server. This class takes care of all 029 * low level details of interacting with an SMTP server and provides 030 * a convenient higher level interface. As with all classes derived 031 * from {@link org.apache.commons.net.SocketClient}, 032 * you must first connect to the server with 033 * {@link org.apache.commons.net.SocketClient#connect connect } 034 * before doing anything, and finally 035 * {@link org.apache.commons.net.SocketClient#disconnect disconnect } 036 * after you're completely finished interacting with the server. 037 * Then you need to check the SMTP reply code to see if the connection 038 * was successful. For example: 039 * <pre> 040 * try { 041 * int reply; 042 * client.connect("mail.foobar.com"); 043 * System.out.print(client.getReplyString()); 044 * 045 * // After connection attempt, you should check the reply code to verify 046 * // success. 047 * reply = client.getReplyCode(); 048 * 049 * if(!SMTPReply.isPositiveCompletion(reply)) { 050 * client.disconnect(); 051 * System.err.println("SMTP server refused connection."); 052 * System.exit(1); 053 * } 054 * 055 * // Do useful stuff here. 056 * ... 057 * } catch(IOException e) { 058 * if(client.isConnected()) { 059 * try { 060 * client.disconnect(); 061 * } catch(IOException f) { 062 * // do nothing 063 * } 064 * } 065 * System.err.println("Could not connect to server."); 066 * e.printStackTrace(); 067 * System.exit(1); 068 * } 069 * </pre> 070 * <p> 071 * Immediately after connecting is the only real time you need to check the 072 * reply code (because connect is of type void). The convention for all the 073 * SMTP command methods in SMTPClient is such that they either return a 074 * boolean value or some other value. 075 * The boolean methods return true on a successful completion reply from 076 * the SMTP server and false on a reply resulting in an error condition or 077 * failure. The methods returning a value other than boolean return a value 078 * containing the higher level data produced by the SMTP command, or null if a 079 * reply resulted in an error condition or failure. If you want to access 080 * the exact SMTP reply code causing a success or failure, you must call 081 * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode } after 082 * a success or failure. 083 * <p> 084 * You should keep in mind that the SMTP server may choose to prematurely 085 * close a connection for various reasons. The SMTPClient class will detect a 086 * premature SMTP server connection closing when it receives a 087 * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } 088 * response to a command. 089 * When that occurs, the method encountering that reply will throw 090 * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} 091 * . 092 * <code>SMTPConectionClosedException</code> 093 * is a subclass of <code> IOException </code> and therefore need not be 094 * caught separately, but if you are going to catch it separately, its 095 * catch block must appear before the more general <code> IOException </code> 096 * catch block. When you encounter an 097 * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} 098 * , you must disconnect the connection with 099 * {@link #disconnect disconnect() } to properly clean up the 100 * system resources used by SMTPClient. Before disconnecting, you may check 101 * the last reply code and text with 102 * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode }, 103 * {@link org.apache.commons.net.smtp.SMTP#getReplyString getReplyString }, 104 * and 105 * {@link org.apache.commons.net.smtp.SMTP#getReplyStrings getReplyStrings}. 106 * <p> 107 * Rather than list it separately for each method, we mention here that 108 * every method communicating with the server and throwing an IOException 109 * can also throw a 110 * {@link org.apache.commons.net.MalformedServerReplyException} 111 * , which is a subclass 112 * of IOException. A MalformedServerReplyException will be thrown when 113 * the reply received from the server deviates enough from the protocol 114 * specification that it cannot be interpreted in a useful manner despite 115 * attempts to be as lenient as possible. 116 * <p> 117 * <p> 118 * @see SMTP 119 * @see SimpleSMTPHeader 120 * @see RelayPath 121 * @see SMTPConnectionClosedException 122 * @see org.apache.commons.net.MalformedServerReplyException 123 ***/ 124 125 public class SMTPClient extends SMTP 126 { 127 128 /** 129 * Default SMTPClient constructor. Creates a new SMTPClient instance. 130 */ 131 public SMTPClient() { } 132 133 /** 134 * Overloaded constructor that takes an encoding specification 135 * @param encoding The encoding to use 136 * @since 2.0 137 */ 138 public SMTPClient(String encoding) { 139 super(encoding); 140 } 141 142 143 /*** 144 * At least one SMTPClient method ({@link #sendMessageData sendMessageData }) 145 * does not complete the entire sequence of SMTP commands to complete a 146 * transaction. These types of commands require some action by the 147 * programmer after the reception of a positive intermediate command. 148 * After the programmer's code completes its actions, it must call this 149 * method to receive the completion reply from the server and verify the 150 * success of the entire transaction. 151 * <p> 152 * For example, 153 * <pre> 154 * writer = client.sendMessage(); 155 * if(writer == null) // failure 156 * return false; 157 * header = 158 * new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo"); 159 * writer.write(header.toString()); 160 * writer.write("This is just a test"); 161 * writer.close(); 162 * if(!client.completePendingCommand()) // failure 163 * return false; 164 * </pre> 165 * <p> 166 * @return True if successfully completed, false if not. 167 * @exception SMTPConnectionClosedException 168 * If the SMTP server prematurely closes the connection as a result 169 * of the client being idle or some other reason causing the server 170 * to send SMTP reply code 421. This exception may be caught either 171 * as an IOException or independently as itself. 172 * @exception IOException If an I/O error occurs while either sending a 173 * command to the server or receiving a reply from the server. 174 ***/ 175 public boolean completePendingCommand() throws IOException 176 { 177 return SMTPReply.isPositiveCompletion(getReply()); 178 } 179 180 181 /*** 182 * Login to the SMTP server by sending the HELO command with the 183 * given hostname as an argument. Before performing any mail commands, 184 * you must first login. 185 * <p> 186 * @param hostname The hostname with which to greet the SMTP server. 187 * @return True if successfully completed, false if not. 188 * @exception SMTPConnectionClosedException 189 * If the SMTP server prematurely closes the connection as a result 190 * of the client being idle or some other reason causing the server 191 * to send SMTP reply code 421. This exception may be caught either 192 * as an IOException or independently as itself. 193 * @exception IOException If an I/O error occurs while either sending a 194 * command to the server or receiving a reply from the server. 195 ***/ 196 public boolean login(String hostname) throws IOException 197 { 198 return SMTPReply.isPositiveCompletion(helo(hostname)); 199 } 200 201 202 /*** 203 * Login to the SMTP server by sending the HELO command with the 204 * client hostname as an argument. Before performing any mail commands, 205 * you must first login. 206 * <p> 207 * @return True if successfully completed, false if not. 208 * @exception SMTPConnectionClosedException 209 * If the SMTP server prematurely closes the connection as a result 210 * of the client being idle or some other reason causing the server 211 * to send SMTP reply code 421. This exception may be caught either 212 * as an IOException or independently as itself. 213 * @exception IOException If an I/O error occurs while either sending a 214 * command to the server or receiving a reply from the server. 215 ***/ 216 public boolean login() throws IOException 217 { 218 String name; 219 InetAddress host; 220 221 host = getLocalAddress(); 222 name = host.getHostName(); 223 224 if (name == null) 225 return false; 226 227 return SMTPReply.isPositiveCompletion(helo(name)); 228 } 229 230 231 /*** 232 * Set the sender of a message using the SMTP MAIL command, specifying 233 * a reverse relay path. The sender must be set first before any 234 * recipients may be specified, otherwise the mail server will reject 235 * your commands. 236 * <p> 237 * @param path The reverse relay path pointing back to the sender. 238 * @return True if successfully completed, false if not. 239 * @exception SMTPConnectionClosedException 240 * If the SMTP server prematurely closes the connection as a result 241 * of the client being idle or some other reason causing the server 242 * to send SMTP reply code 421. This exception may be caught either 243 * as an IOException or independently as itself. 244 * @exception IOException If an I/O error occurs while either sending a 245 * command to the server or receiving a reply from the server. 246 ***/ 247 public boolean setSender(RelayPath path) throws IOException 248 { 249 return SMTPReply.isPositiveCompletion(mail(path.toString())); 250 } 251 252 253 /*** 254 * Set the sender of a message using the SMTP MAIL command, specifying 255 * the sender's email address. The sender must be set first before any 256 * recipients may be specified, otherwise the mail server will reject 257 * your commands. 258 * <p> 259 * @param address The sender's email address. 260 * @return True if successfully completed, false if not. 261 * @exception SMTPConnectionClosedException 262 * If the SMTP server prematurely closes the connection as a result 263 * of the client being idle or some other reason causing the server 264 * to send SMTP reply code 421. This exception may be caught either 265 * as an IOException or independently as itself. 266 * @exception IOException If an I/O error occurs while either sending a 267 * command to the server or receiving a reply from the server. 268 ***/ 269 public boolean setSender(String address) throws IOException 270 { 271 return SMTPReply.isPositiveCompletion(mail("<" + address + ">")); 272 } 273 274 275 /*** 276 * Add a recipient for a message using the SMTP RCPT command, specifying 277 * a forward relay path. The sender must be set first before any 278 * recipients may be specified, otherwise the mail server will reject 279 * your commands. 280 * <p> 281 * @param path The forward relay path pointing to the recipient. 282 * @return True if successfully completed, false if not. 283 * @exception SMTPConnectionClosedException 284 * If the SMTP server prematurely closes the connection as a result 285 * of the client being idle or some other reason causing the server 286 * to send SMTP reply code 421. This exception may be caught either 287 * as an IOException or independently as itself. 288 * @exception IOException If an I/O error occurs while either sending a 289 * command to the server or receiving a reply from the server. 290 ***/ 291 public boolean addRecipient(RelayPath path) throws IOException 292 { 293 return SMTPReply.isPositiveCompletion(rcpt(path.toString())); 294 } 295 296 297 /*** 298 * Add a recipient for a message using the SMTP RCPT command, the 299 * recipient's email address. The sender must be set first before any 300 * recipients may be specified, otherwise the mail server will reject 301 * your commands. 302 * <p> 303 * @param address The recipient's email address. 304 * @return True if successfully completed, false if not. 305 * @exception SMTPConnectionClosedException 306 * If the SMTP server prematurely closes the connection as a result 307 * of the client being idle or some other reason causing the server 308 * to send SMTP reply code 421. This exception may be caught either 309 * as an IOException or independently as itself. 310 * @exception IOException If an I/O error occurs while either sending a 311 * command to the server or receiving a reply from the server. 312 ***/ 313 public boolean addRecipient(String address) throws IOException 314 { 315 return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">")); 316 } 317 318 319 320 /*** 321 * Send the SMTP DATA command in preparation to send an email message. 322 * This method returns a DotTerminatedMessageWriter instance to which 323 * the message can be written. Null is returned if the DATA command 324 * fails. 325 * <p> 326 * You must not issue any commands to the SMTP server (i.e., call any 327 * (other methods) until you finish writing to the returned Writer 328 * instance and close it. The SMTP protocol uses the same stream for 329 * issuing commands as it does for returning results. Therefore the 330 * returned Writer actually writes directly to the SMTP connection. 331 * After you close the writer, you can execute new commands. If you 332 * do not follow these requirements your program will not work properly. 333 * <p> 334 * You can use the provided 335 * {@link org.apache.commons.net.smtp.SimpleSMTPHeader} 336 * class to construct a bare minimum header. 337 * To construct more complicated headers you should 338 * refer to RFC 822. When the Java Mail API is finalized, you will be 339 * able to use it to compose fully compliant Internet text messages. 340 * The DotTerminatedMessageWriter takes care of doubling line-leading 341 * dots and ending the message with a single dot upon closing, so all 342 * you have to worry about is writing the header and the message. 343 * <p> 344 * Upon closing the returned Writer, you need to call 345 * {@link #completePendingCommand completePendingCommand() } 346 * to finalize the transaction and verify its success or failure from 347 * the server reply. 348 * <p> 349 * @return A DotTerminatedMessageWriter to which the message (including 350 * header) can be written. Returns null if the command fails. 351 * @exception SMTPConnectionClosedException 352 * If the SMTP server prematurely closes the connection as a result 353 * of the client being idle or some other reason causing the server 354 * to send SMTP reply code 421. This exception may be caught either 355 * as an IOException or independently as itself. 356 * @exception IOException If an I/O error occurs while either sending a 357 * command to the server or receiving a reply from the server. 358 ***/ 359 public Writer sendMessageData() throws IOException 360 { 361 if (!SMTPReply.isPositiveIntermediate(data())) 362 return null; 363 364 return new DotTerminatedMessageWriter(_writer); 365 } 366 367 368 /*** 369 * A convenience method for sending short messages. This method fetches 370 * the Writer returned by {@link #sendMessageData sendMessageData() } 371 * and writes the specified String to it. After writing the message, 372 * this method calls {@link #completePendingCommand completePendingCommand() } 373 * to finalize the transaction and returns 374 * its success or failure. 375 * <p> 376 * @param message The short email message to send. 377 * @return True if successfully completed, false if not. 378 * @exception SMTPConnectionClosedException 379 * If the SMTP server prematurely closes the connection as a result 380 * of the client being idle or some other reason causing the server 381 * to send SMTP reply code 421. This exception may be caught either 382 * as an IOException or independently as itself. 383 * @exception IOException If an I/O error occurs while either sending a 384 * command to the server or receiving a reply from the server. 385 ***/ 386 public boolean sendShortMessageData(String message) throws IOException 387 { 388 Writer writer; 389 390 writer = sendMessageData(); 391 392 if (writer == null) 393 return false; 394 395 writer.write(message); 396 writer.close(); 397 398 return completePendingCommand(); 399 } 400 401 402 /*** 403 * A convenience method for a sending short email without having to 404 * explicitly set the sender and recipient(s). This method 405 * sets the sender and recipient using 406 * {@link #setSender setSender } and 407 * {@link #addRecipient addRecipient }, and then sends the 408 * message using {@link #sendShortMessageData sendShortMessageData }. 409 * <p> 410 * @param sender The email address of the sender. 411 * @param recipient The email address of the recipient. 412 * @param message The short email message to send. 413 * @return True if successfully completed, false if not. 414 * @exception SMTPConnectionClosedException 415 * If the SMTP server prematurely closes the connection as a result 416 * of the client being idle or some other reason causing the server 417 * to send SMTP reply code 421. This exception may be caught either 418 * as an IOException or independently as itself. 419 * @exception IOException If an I/O error occurs while either sending a 420 * command to the server or receiving a reply from the server. 421 ***/ 422 public boolean sendSimpleMessage(String sender, String recipient, 423 String message) 424 throws IOException 425 { 426 if (!setSender(sender)) 427 return false; 428 429 if (!addRecipient(recipient)) 430 return false; 431 432 return sendShortMessageData(message); 433 } 434 435 436 437 /*** 438 * A convenience method for a sending short email without having to 439 * explicitly set the sender and recipient(s). This method 440 * sets the sender and recipients using 441 * {@link #setSender setSender } and 442 * {@link #addRecipient addRecipient }, and then sends the 443 * message using {@link #sendShortMessageData sendShortMessageData }. 444 * <p> 445 * @param sender The email address of the sender. 446 * @param recipients An array of recipient email addresses. 447 * @param message The short email message to send. 448 * @return True if successfully completed, false if not. 449 * @exception SMTPConnectionClosedException 450 * If the SMTP server prematurely closes the connection as a result 451 * of the client being idle or some other reason causing the server 452 * to send SMTP reply code 421. This exception may be caught either 453 * as an IOException or independently as itself. 454 * @exception IOException If an I/O error occurs while either sending a 455 * command to the server or receiving a reply from the server. 456 ***/ 457 public boolean sendSimpleMessage(String sender, String[] recipients, 458 String message) 459 throws IOException 460 { 461 boolean oneSuccess = false; 462 int count; 463 464 if (!setSender(sender)) 465 return false; 466 467 for (count = 0; count < recipients.length; count++) 468 { 469 if (addRecipient(recipients[count])) 470 oneSuccess = true; 471 } 472 473 if (!oneSuccess) 474 return false; 475 476 return sendShortMessageData(message); 477 } 478 479 480 /*** 481 * Logout of the SMTP server by sending the QUIT command. 482 * <p> 483 * @return True if successfully completed, false if not. 484 * @exception SMTPConnectionClosedException 485 * If the SMTP server prematurely closes the connection as a result 486 * of the client being idle or some other reason causing the server 487 * to send SMTP reply code 421. This exception may be caught either 488 * as an IOException or independently as itself. 489 * @exception IOException If an I/O error occurs while either sending a 490 * command to the server or receiving a reply from the server. 491 ***/ 492 public boolean logout() throws IOException 493 { 494 return SMTPReply.isPositiveCompletion(quit()); 495 } 496 497 498 499 /*** 500 * Aborts the current mail transaction, resetting all server stored 501 * sender, recipient, and mail data, cleaing all buffers and tables. 502 * <p> 503 * @return True if successfully completed, false if not. 504 * @exception SMTPConnectionClosedException 505 * If the SMTP server prematurely closes the connection as a result 506 * of the client being idle or some other reason causing the server 507 * to send SMTP reply code 421. This exception may be caught either 508 * as an IOException or independently as itself. 509 * @exception IOException If an I/O error occurs while either sending a 510 * command to the server or receiving a reply from the server. 511 ***/ 512 public boolean reset() throws IOException 513 { 514 return SMTPReply.isPositiveCompletion(rset()); 515 } 516 517 518 /*** 519 * Verify that a username or email address is valid, i.e., that mail 520 * can be delivered to that mailbox on the server. 521 * <p> 522 * @param username The username or email address to validate. 523 * @return True if the username is valid, false if not. 524 * @exception SMTPConnectionClosedException 525 * If the SMTP server prematurely closes the connection as a result 526 * of the client being idle or some other reason causing the server 527 * to send SMTP reply code 421. This exception may be caught either 528 * as an IOException or independently as itself. 529 * @exception IOException If an I/O error occurs while either sending a 530 * command to the server or receiving a reply from the server. 531 ***/ 532 public boolean verify(String username) throws IOException 533 { 534 int result; 535 536 result = vrfy(username); 537 538 return (result == SMTPReply.ACTION_OK || 539 result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD); 540 } 541 542 543 /*** 544 * Fetches the system help information from the server and returns the 545 * full string. 546 * <p> 547 * @return The system help string obtained from the server. null if the 548 * information could not be obtained. 549 * @exception SMTPConnectionClosedException 550 * If the SMTP server prematurely closes the connection as a result 551 * of the client being idle or some other reason causing the server 552 * to send SMTP reply code 421. This exception may be caught either 553 * as an IOException or independently as itself. 554 * @exception IOException If an I/O error occurs while either sending a 555 * command to the server or receiving a reply from the server. 556 ***/ 557 public String listHelp() throws IOException 558 { 559 if (SMTPReply.isPositiveCompletion(help())) 560 return getReplyString(); 561 return null; 562 } 563 564 565 /*** 566 * Fetches the help information for a given command from the server and 567 * returns the full string. 568 * <p> 569 * @param command The command on which to ask for help. 570 * @return The command help string obtained from the server. null if the 571 * information could not be obtained. 572 * @exception SMTPConnectionClosedException 573 * If the SMTP server prematurely closes the connection as a result 574 * of the client being idle or some other reason causing the server 575 * to send SMTP reply code 421. This exception may be caught either 576 * as an IOException or independently as itself. 577 * @exception IOException If an I/O error occurs while either sending a 578 * command to the server or receiving a reply from the server. 579 ***/ 580 public String listHelp(String command) throws IOException 581 { 582 if (SMTPReply.isPositiveCompletion(help(command))) 583 return getReplyString(); 584 return null; 585 } 586 587 588 /*** 589 * Sends a NOOP command to the SMTP server. This is useful for preventing 590 * server timeouts. 591 * <p> 592 * @return True if successfully completed, false if not. 593 * @exception SMTPConnectionClosedException 594 * If the SMTP server prematurely closes the connection as a result 595 * of the client being idle or some other reason causing the server 596 * to send SMTP reply code 421. This exception may be caught either 597 * as an IOException or independently as itself. 598 * @exception IOException If an I/O error occurs while either sending a 599 * command to the server or receiving a reply from the server. 600 ***/ 601 public boolean sendNoOp() throws IOException 602 { 603 return SMTPReply.isPositiveCompletion(noop()); 604 } 605 606 }