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 018package org.apache.commons.net.smtp; 019 020import java.io.IOException; 021import java.io.Writer; 022import java.net.InetAddress; 023 024import 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 * 117 * @see SMTP 118 * @see SimpleSMTPHeader 119 * @see RelayPath 120 * @see SMTPConnectionClosedException 121 * @see org.apache.commons.net.MalformedServerReplyException 122 */ 123 124public class SMTPClient extends SMTP 125{ 126 127 /** 128 * Default SMTPClient constructor. Creates a new SMTPClient instance. 129 */ 130 public SMTPClient() { } 131 132 /** 133 * Overloaded constructor that takes an encoding specification 134 * @param encoding The encoding to use 135 * @since 2.0 136 */ 137 public SMTPClient(final String encoding) { 138 super(encoding); 139 } 140 141 142 /** 143 * At least one SMTPClient method ({@link #sendMessageData sendMessageData }) 144 * does not complete the entire sequence of SMTP commands to complete a 145 * transaction. These types of commands require some action by the 146 * programmer after the reception of a positive intermediate command. 147 * After the programmer's code completes its actions, it must call this 148 * method to receive the completion reply from the server and verify the 149 * success of the entire transaction. 150 * <p> 151 * For example, 152 * <pre> 153 * writer = client.sendMessageData(); 154 * if(writer == null) // failure 155 * return false; 156 * header = 157 * new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo"); 158 * writer.write(header.toString()); 159 * writer.write("This is just a test"); 160 * writer.close(); 161 * if(!client.completePendingCommand()) // failure 162 * return false; 163 * </pre> 164 * <p> 165 * @return True if successfully completed, false if not. 166 * @throws SMTPConnectionClosedException 167 * If the SMTP server prematurely closes the connection as a result 168 * of the client being idle or some other reason causing the server 169 * to send SMTP reply code 421. This exception may be caught either 170 * as an IOException or independently as itself. 171 * @throws IOException If an I/O error occurs while either sending a 172 * command to the server or receiving a reply from the server. 173 */ 174 public boolean completePendingCommand() throws IOException 175 { 176 return SMTPReply.isPositiveCompletion(getReply()); 177 } 178 179 180 /** 181 * Login to the SMTP server by sending the HELO command with the 182 * given hostname as an argument. Before performing any mail commands, 183 * you must first login. 184 * <p> 185 * @param hostname The hostname with which to greet the SMTP server. 186 * @return True if successfully completed, false if not. 187 * @throws SMTPConnectionClosedException 188 * If the SMTP server prematurely closes the connection as a result 189 * of the client being idle or some other reason causing the server 190 * to send SMTP reply code 421. This exception may be caught either 191 * as an IOException or independently as itself. 192 * @throws IOException If an I/O error occurs while either sending a 193 * command to the server or receiving a reply from the server. 194 */ 195 public boolean login(final String hostname) throws IOException 196 { 197 return SMTPReply.isPositiveCompletion(helo(hostname)); 198 } 199 200 201 /** 202 * Login to the SMTP server by sending the HELO command with the 203 * client hostname as an argument. Before performing any mail commands, 204 * you must first login. 205 * <p> 206 * @return True if successfully completed, false if not. 207 * @throws SMTPConnectionClosedException 208 * If the SMTP server prematurely closes the connection as a result 209 * of the client being idle or some other reason causing the server 210 * to send SMTP reply code 421. This exception may be caught either 211 * as an IOException or independently as itself. 212 * @throws IOException If an I/O error occurs while either sending a 213 * command to the server or receiving a reply from the server. 214 */ 215 public boolean login() throws IOException 216 { 217 final String name; 218 final InetAddress host; 219 220 host = getLocalAddress(); 221 name = host.getHostName(); 222 223 if (name == null) { 224 return false; 225 } 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 * @throws 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 * @throws 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(final 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 * @throws 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 * @throws 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(final 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 * @throws 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 * @throws 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(final 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 * @throws 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 * @throws 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(final 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 5322. 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 * @throws 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 * @throws IOException If an I/O error occurs while either sending a 357 * command to the server or receiving a reply from the server. 358 * @see #sendShortMessageData(String) 359 */ 360 public Writer sendMessageData() throws IOException 361 { 362 if (!SMTPReply.isPositiveIntermediate(data())) { 363 return null; 364 } 365 366 return new DotTerminatedMessageWriter(writer); 367 } 368 369 370 /** 371 * A convenience method for sending short messages. This method fetches 372 * the Writer returned by {@link #sendMessageData sendMessageData() } 373 * and writes the specified String to it. After writing the message, 374 * this method calls {@link #completePendingCommand completePendingCommand() } 375 * to finalize the transaction and returns 376 * its success or failure. 377 * <p> 378 * @param message The short email message to send. 379 * This must include the headers and the body, but not the trailing "." 380 * @return True if successfully completed, false if not. 381 * @throws SMTPConnectionClosedException 382 * If the SMTP server prematurely closes the connection as a result 383 * of the client being idle or some other reason causing the server 384 * to send SMTP reply code 421. This exception may be caught either 385 * as an IOException or independently as itself. 386 * @throws IOException If an I/O error occurs while either sending a 387 * command to the server or receiving a reply from the server. 388 */ 389 public boolean sendShortMessageData(final String message) throws IOException 390 { 391 try (final Writer writer = sendMessageData()) { 392 393 if (writer == null) { 394 return false; 395 } 396 397 writer.write(message); 398 } 399 400 return completePendingCommand(); 401 } 402 403 404 /** 405 * A convenience method for a sending short email without having to 406 * explicitly set the sender and recipient(s). This method 407 * sets the sender and recipient using 408 * {@link #setSender setSender } and 409 * {@link #addRecipient addRecipient }, and then sends the 410 * message using {@link #sendShortMessageData sendShortMessageData }. 411 * <p> 412 * @param sender The email address of the sender. 413 * @param recipient The email address of the recipient. 414 * @param message The short email message to send. 415 * This must include the headers and the body, but not the trailing "." 416 * @return True if successfully completed, false if not. 417 * @throws SMTPConnectionClosedException 418 * If the SMTP server prematurely closes the connection as a result 419 * of the client being idle or some other reason causing the server 420 * to send SMTP reply code 421. This exception may be caught either 421 * as an IOException or independently as itself. 422 * @throws IOException If an I/O error occurs while either sending a 423 * command to the server or receiving a reply from the server. 424 */ 425 public boolean sendSimpleMessage(final String sender, final String recipient, 426 final String message) 427 throws IOException 428 { 429 if (!setSender(sender)) { 430 return false; 431 } 432 433 if (!addRecipient(recipient)) { 434 return false; 435 } 436 437 return sendShortMessageData(message); 438 } 439 440 441 442 /** 443 * A convenience method for a sending short email without having to 444 * explicitly set the sender and recipient(s). This method 445 * sets the sender and recipients using 446 * {@link #setSender(String) setSender} and 447 * {@link #addRecipient(String) addRecipient}, and then sends the 448 * message using {@link #sendShortMessageData(String) sendShortMessageData}. 449 * <p> 450 * Note that the method ignores failures when calling 451 * {@link #addRecipient(String) addRecipient} so long as 452 * at least one call succeeds. If no recipients can be successfully 453 * added then the method will fail (and does not attempt to 454 * send the message) 455 * <p> 456 * @param sender The email address of the sender. 457 * @param recipients An array of recipient email addresses. 458 * @param message The short email message to send. 459 * This must include the headers and the body, but not the trailing "." 460 * @return True if successfully completed, false if not. 461 * @throws SMTPConnectionClosedException 462 * If the SMTP server prematurely closes the connection as a result 463 * of the client being idle or some other reason causing the server 464 * to send SMTP reply code 421. This exception may be caught either 465 * as an IOException or independently as itself. 466 * @throws IOException If an I/O error occurs while either sending a 467 * command to the server or receiving a reply from the server. 468 */ 469 public boolean sendSimpleMessage(final String sender, final String[] recipients, 470 final String message) 471 throws IOException 472 { 473 boolean oneSuccess = false; 474 int count; 475 476 if (!setSender(sender)) { 477 return false; 478 } 479 480 for (count = 0; count < recipients.length; count++) 481 { 482 if (addRecipient(recipients[count])) { 483 oneSuccess = true; 484 } 485 } 486 487 if (!oneSuccess) { 488 return false; 489 } 490 491 return sendShortMessageData(message); 492 } 493 494 495 /** 496 * Logout of the SMTP server by sending the QUIT command. 497 * <p> 498 * @return True if successfully completed, false if not. 499 * @throws SMTPConnectionClosedException 500 * If the SMTP server prematurely closes the connection as a result 501 * of the client being idle or some other reason causing the server 502 * to send SMTP reply code 421. This exception may be caught either 503 * as an IOException or independently as itself. 504 * @throws IOException If an I/O error occurs while either sending a 505 * command to the server or receiving a reply from the server. 506 */ 507 public boolean logout() throws IOException 508 { 509 return SMTPReply.isPositiveCompletion(quit()); 510 } 511 512 513 514 /** 515 * Aborts the current mail transaction, resetting all server stored 516 * sender, recipient, and mail data, cleaing all buffers and tables. 517 * <p> 518 * @return True if successfully completed, false if not. 519 * @throws SMTPConnectionClosedException 520 * If the SMTP server prematurely closes the connection as a result 521 * of the client being idle or some other reason causing the server 522 * to send SMTP reply code 421. This exception may be caught either 523 * as an IOException or independently as itself. 524 * @throws IOException If an I/O error occurs while either sending a 525 * command to the server or receiving a reply from the server. 526 */ 527 public boolean reset() throws IOException 528 { 529 return SMTPReply.isPositiveCompletion(rset()); 530 } 531 532 533 /** 534 * Verify that a username or email address is valid, i.e., that mail 535 * can be delivered to that mailbox on the server. 536 * <p> 537 * @param username The username or email address to validate. 538 * @return True if the username is valid, false if not. 539 * @throws SMTPConnectionClosedException 540 * If the SMTP server prematurely closes the connection as a result 541 * of the client being idle or some other reason causing the server 542 * to send SMTP reply code 421. This exception may be caught either 543 * as an IOException or independently as itself. 544 * @throws IOException If an I/O error occurs while either sending a 545 * command to the server or receiving a reply from the server. 546 */ 547 public boolean verify(final String username) throws IOException 548 { 549 final int result; 550 551 result = vrfy(username); 552 553 return result == SMTPReply.ACTION_OK || 554 result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD; 555 } 556 557 558 /** 559 * Fetches the system help information from the server and returns the 560 * full string. 561 * <p> 562 * @return The system help string obtained from the server. null if the 563 * information could not be obtained. 564 * @throws SMTPConnectionClosedException 565 * If the SMTP server prematurely closes the connection as a result 566 * of the client being idle or some other reason causing the server 567 * to send SMTP reply code 421. This exception may be caught either 568 * as an IOException or independently as itself. 569 * @throws IOException If an I/O error occurs while either sending a 570 * command to the server or receiving a reply from the server. 571 */ 572 public String listHelp() throws IOException 573 { 574 if (SMTPReply.isPositiveCompletion(help())) { 575 return getReplyString(); 576 } 577 return null; 578 } 579 580 581 /** 582 * Fetches the help information for a given command from the server and 583 * returns the full string. 584 * <p> 585 * @param command The command on which to ask for help. 586 * @return The command help string obtained from the server. null if the 587 * information could not be obtained. 588 * @throws SMTPConnectionClosedException 589 * If the SMTP server prematurely closes the connection as a result 590 * of the client being idle or some other reason causing the server 591 * to send SMTP reply code 421. This exception may be caught either 592 * as an IOException or independently as itself. 593 * @throws IOException If an I/O error occurs while either sending a 594 * command to the server or receiving a reply from the server. 595 */ 596 public String listHelp(final String command) throws IOException 597 { 598 if (SMTPReply.isPositiveCompletion(help(command))) { 599 return getReplyString(); 600 } 601 return null; 602 } 603 604 605 /** 606 * Sends a NOOP command to the SMTP server. This is useful for preventing 607 * server timeouts. 608 * <p> 609 * @return True if successfully completed, false if not. 610 * @throws SMTPConnectionClosedException 611 * If the SMTP server prematurely closes the connection as a result 612 * of the client being idle or some other reason causing the server 613 * to send SMTP reply code 421. This exception may be caught either 614 * as an IOException or independently as itself. 615 * @throws IOException If an I/O error occurs while either sending a 616 * command to the server or receiving a reply from the server. 617 */ 618 public boolean sendNoOp() throws IOException 619 { 620 return SMTPReply.isPositiveCompletion(noop()); 621 } 622 623}