Selenium WebDriver using JavaScript - selenium-webdriver

I'm new to Selenium WebDriver and trying to automate the online shopping site "amazon.co.uk". My intention is to navigate to a particular page of the site and retrieve the sellers names,their respective URL's and write the final output to an Excel Sheet. I was able to print all the above mentioned details in the console but couldn't write them into an Excel Sheet.
Below is the piece of code that I had come up with:
package Selenium.src.com.amazon.automation;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
public class AmazonTest {
public static void main(String[] args) throws InterruptedException, IOException {
WebDriver driver = new FirefoxDriver();
try {
driver.get("https://www.amazon.co.uk");
Thread.sleep(1000);;
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(150, TimeUnit.SECONDS);
String PageTitle = driver.getTitle();
System.out.println("Page Title is :" + PageTitle );
} catch (Exception e) {
e.printStackTrace();
System.out.println("Driver not reachable");
}
WebElement wb = driver.findElement(By.xpath("//span[text()='Shop by']"));
WebElement wb1 = driver.findElement(By.xpath("//span[text()='Electronics & Computers']"));
Actions act = new Actions(driver);
act.moveToElement(wb).build().perform();
act.moveToElement(wb1).build().perform();
driver.findElement(By.xpath("//span[text()='Headphones']")).click();
Thread.sleep(2000);
// To wait until the next page loads
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
JavascriptExecutor jse = (JavascriptExecutor)driver;
jse.executeScript("scroll(0, 1000);");
driver.findElement(By.xpath("(//span[text()='See more'])[2]")).click();
List<WebElement> topSellers = driver.findElements(By.xpath("//div[#id='refinementList']//a"));
// int sellersCount = topSellers.size();
System.out.println("The Number Of Top Sellers is :" + topSellers.size());
for(int i=0;i<topSellers.size();i++)
{
//To print the list of Top Sellers and their number of products
System.out.println(topSellers.get(i).getText());
//To print the link of individual seller
System.out.println(topSellers.get(i).getAttribute("href"));
/*To get the page title for individual seller
String PageTitle = driver.getTitle();
System.out.println("Page Tile for this seller is :" +PageTitle);
topSellers.get(i).click();
Thread.sleep(2000);
driver.navigate().back();
WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.titleIs("Amazon.co.uk: see all sellers"));
driver.navigate().refresh();*/
}
driver.close();
}
}
Can anybody please help me to achieve this requirement
I'm trying to write the below mentioned data into the Excel sheet...
1. Seller Name
2. Number of products of the seller
3. href link for individual seller
Please find the Screenshot for the same.
Image shows the list of TopSellers and the count of their products

Related

Why can't Selenium Web Driver find the elements in this case?

Selenium newbie here. The examples I tried so far worked well but now I stumbled upon a case that seemingly doesn't work:
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
public class GeckoDriverTest
{
public static void main(String[] args) throws Throwable
{
System.setProperty("webdriver.gecko.driver", "D://XXX/seleniumdrivers/geckodriver.exe");
FirefoxDriver driver=new FirefoxDriver();
driver.manage().window().maximize();
driver.get("https://www.aerzen.com/de/karriere/stellenangebote.html");
System.out.println("URL = "+driver.getCurrentUrl());
Thread.sleep(3000);
driver.findElement(By.cssSelector("a.consent-banner--accept.button.submit")).click();
Thread.sleep(3000);
System.out.println("URL = "+driver.getCurrentUrl());
List<WebElement> elements = driver.findElements(By.cssSelector("tr > td > a"));
System.out.println("Elements: "+elements.size());
for(WebElement element : elements)
{
String url = element.getAttribute("href");
System.out.println(url);
}
}
}
The first part does work but the "tr > td > a" selector doesn't find any elements although I'm pretty sure they exist (I can see them in the browser window).
Any idea what's going wrong there? Thanks a lot.
The table is inside an iframe. In order to access these elements you will need to switch to that iframe.
Also instead of tr > td > a cssSelector try using table td.real_table_col1 a cssSelector.
This should work better:
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//iframe")));
driver.switchTo().frame(driver.findElement(By.xpath("//iframe")));
List<WebElement> elements = driver.findElements(By.cssSelector("table td.real_table_col1 a"));
System.out.println("Elements: "+elements.size());
for(WebElement element : elements)
{
String url = element.getAttribute("href");
System.out.println(url);
}
Also instead of hardcoded pauses like
Thread.sleep(3000);
You should use ExpectedConditions something like
WebdriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("a.consent-banner--accept.button.submit")));

Trying to automate gmail signup page using selenium webdriver in java

This is how far I have been. But, I am having hard time automating the texts that are in drop-down menu. I tried to automate using select statements, but with no success. I used select while automating facebook signup page and it worked. Following is the code I used during the process
package signUp;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.support.ui.Select;
import org.testng.annotations.Test;
import java.util.List;
/**
* Created by san on 4/18/17.
*/
public class LoginCredintials {
#Test
public void GoogleSignup(){
System.setProperty("webdriver.gecko.driver", "/Users/abc/Downloads/geckodriver");
WebDriver driver = new FirefoxDriver();
String baseUrl = "https://accounts.google.com/SignUp?service=mail&continue=https%3A%2F%2Fmail.google.com%2Fmail%2F&ltmpl=default";
driver.get(baseUrl);
//By ID Text area1
WebElement text1 = driver.findElement(By.id("FirstName"));
text1.clear();
text1.sendKeys("San ");
WebElement text2 = driver.findElement(By.id("LastName"));
text2.clear();
text2.sendKeys("P");
WebElement text3 = driver.findElement(By.xpath(".//*[#id='GmailAddress']"));
text3.clear();
text3.sendKeys("s20077");
WebElement text4 = driver.findElement(By.xpath(".//*[#id='Passwd']"));
text4.clear();
text4.sendKeys("123abcdxy");
WebElement text5 = driver.findElement(By.xpath(".//*[#id='PasswdAgain']"));
text5.clear();
text5.sendKeys("123abcdxy");
WebElement text6 = driver.findElement(By.id("BirthDay"));
text6.clear();
text6.sendKeys("1");
WebElement text7 = driver.findElement(By.id("BirthYear"));
text7.clear();
text7.sendKeys("2000");
WebElement text8 = driver.findElement(By.id("RecoveryPhoneNumber"));
text8.clear();
text8.sendKeys("9222103436");
WebElement text9 = driver.findElement(By.id("RecoveryEmailAddress"));
text9.clear();
text9.sendKeys("abc_gh#yahoo.com");
Select droplist1 = new Select(driver.findElement(By.id("gender")));
droplist1.selectByVisibleText("Male");
Select droplist2 = new Select(driver.findElement(By.id("BirthMonth")));
droplist2.selectByVisibleText("March");
Select droplist3 = new Select(driver.findElement(By.xpath(".//*[#id='CountryCode']/div")));
droplist3.selectByVisibleText("United States");
WebElement text10 = driver.findElement(By.id("submitbutton"));
text10.click();
}
}
You will have to write a custom method for selecting values from the required drop-downs, as they are not standard select components. Hence, you need to first click on the dropdown and wait for the options to appear. Once, the options are visible, you can click on the required option. I have written a generic method 'googleSelect' for this purpose below:
package signUp;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.Test;
/**
* Created by san on 4/18/17.
*/
public class LoginCredintials {
static WebDriver driver = null;
#Test
public void GoogleSignup(){
System.setProperty("webdriver.gecko.driver", "/Users/abc/Downloads/geckodriver");
driver = new FirefoxDriver();
String baseUrl = "https://accounts.google.com/SignUp?service=mail&continue=https%3A%2F%2Fmail.google.com%2Fmail%2F&ltmpl=default";
driver.get(baseUrl);
//By ID Text area1
WebElement text1 = driver.findElement(By.id("FirstName"));
text1.clear();
text1.sendKeys("San ");
WebElement text2 = driver.findElement(By.id("LastName"));
text2.clear();
text2.sendKeys("P");
WebElement text3 = driver.findElement(By.xpath(".//*[#id='GmailAddress']"));
text3.clear();
text3.sendKeys("s20077444");
WebElement text4 = driver.findElement(By.xpath(".//*[#id='Passwd']"));
text4.clear();
text4.sendKeys("123abcdxy");
WebElement text5 = driver.findElement(By.xpath(".//*[#id='PasswdAgain']"));
text5.clear();
text5.sendKeys("123abcdxy");
WebElement text6 = driver.findElement(By.id("BirthDay"));
text6.clear();
text6.sendKeys("1");
WebElement text7 = driver.findElement(By.id("BirthYear"));
text7.clear();
text7.sendKeys("2000");
WebElement text8 = driver.findElement(By.id("RecoveryPhoneNumber"));
text8.clear();
text8.sendKeys("9222103436");
WebElement text9 = driver.findElement(By.id("RecoveryEmailAddress"));
text9.clear();
text9.sendKeys("abc_gh#yahoo.com");
googleSelect(By.id("Gender"), "Male");
googleSelect(By.id("BirthMonth"), "March");
googleSelect(By.xpath(".//*[#id='CountryCode']/div"), "United States");
WebElement text10 = driver.findElement(By.id("submitbutton"));
text10.click();
driver.quit();
}
private static void googleSelect(By by, String text) {
driver.findElement(by).click();
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOf(
driver.findElement(By.xpath("//div[#class='goog-menu goog-menu-vertical']//div[text()='" + text + "']"))));
driver.findElement(By.xpath("//div[#class='goog-menu goog-menu-vertical']//div[text()='" + text + "']")).click();
}
}
Try above code and let me know, if it works for you.
Check the html side of the page. Sometimes check boxes are written as links. So you have to click on the drop down first and click on the element you have to select. I may not be right but if you can please check.
just saw the signup page. looks like it's made up div and li elements so Select won't work. i also saw values being set into hidden fields like "HiddenGender", "HiddenBirthMonth". try developer tools inspect element on chrome to get the fields you require and set the values to these hidden elements directly. Hope this helps.

How to attach Failed Test Case screen shot using reporter.log() in the TestNG Index.html report

am using a static method to take screen shot and using reporter.log function attaching the screen shot to the index.html report of testNg. Here is the code for taking screen shot.
public class GenericHelper extends CNLogin {
public static String takeScreenShot(String methodName){
try {
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
// C:\Users\499290\AppData\Local\Temp\screenshot7520341205731631960.png
String FilePath = "C:\\Users\\499290\\Downloads\\CNProject1\\CNProject\\test-output\\";
new File(FilePath);
FileUtils.copyFile(scrFile, new File( FilePath +methodName +".jpg") );
System.out.println("***Placed screen shot in "+scrFile+" ***");
}
catch(IOException e) {
e.printStackTrace();
}
return methodName+".jpg";
}
}
Am attching the screen shot by using the below code in the index.html report
String TakescreenShot = GenericHelper.takeScreenShot("AddNewPr");
Reporter.log("<a href=\"" + TakescreenShot + "\"><p align=\"left\">Add New PR screenshot at " + new Date()+ "</p>");
am not able to take screen shot when a test case is failed neither the screen shot is getting attached to the report.
Here is my test case if it got passed my screen shot method will take the screen shot and attach the screen shot in the report but when its failed not sure how to take the screen shot.
public void MultipleServiceDelete() throws InterruptedException {
driver.findElement(By.id("page:frm:pageB:repeatUpper:0:repeat:0:chkIsDelete")).click();
Thread.sleep(5000);
driver.findElement(By.id("page:frm:pageB:btnDeleteMultipleServices")).click();
String DeleteService = ScreenShot.takeScreenShot("MultipleServiceDelete");
Reporter.log("<a href=\"" + DeleteService + "\"><p align=\"left\"> Delete Service screenshot at " + new Date()+ "</p>");
}
You will want to add a TestNG listener that takes a screenshot when the test fails. Here is some code for a listener taken from my Selenium Maven Template:
package com.lazerycode.selenium.listeners;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.Augmenter;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import static com.lazerycode.selenium.DriverFactory.getDriver;
public class ScreenshotListener extends TestListenerAdapter {
private boolean createFile(File screenshot) {
boolean fileCreated = false;
if (screenshot.exists()) {
fileCreated = true;
} else {
File parentDirectory = new File(screenshot.getParent());
if (parentDirectory.exists() || parentDirectory.mkdirs()) {
try {
fileCreated = screenshot.createNewFile();
} catch (IOException errorCreatingScreenshot) {
errorCreatingScreenshot.printStackTrace();
}
}
}
return fileCreated;
}
private void writeScreenshotToFile(WebDriver driver, File screenshot) {
try {
FileOutputStream screenshotStream = new FileOutputStream(screenshot);
screenshotStream.write(((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES));
screenshotStream.close();
} catch (IOException unableToWriteScreenshot) {
System.err.println("Unable to write " + screenshot.getAbsolutePath());
unableToWriteScreenshot.printStackTrace();
}
}
#Override
public void onTestFailure(ITestResult failingTest) {
try {
WebDriver driver = getDriver();
String screenshotDirectory = System.getProperty("screenshotDirectory");
String screenshotAbsolutePath = screenshotDirectory + File.separator + System.currentTimeMillis() + "_" + failingTest.getName() + ".png";
File screenshot = new File(screenshotAbsolutePath);
if (createFile(screenshot)) {
try {
writeScreenshotToFile(driver, screenshot);
} catch (ClassCastException weNeedToAugmentOurDriverObject) {
writeScreenshotToFile(new Augmenter().augment(driver), screenshot);
}
System.out.println("Written screenshot to " + screenshotAbsolutePath);
} else {
System.err.println("Unable to create " + screenshotAbsolutePath);
}
} catch (Exception ex) {
System.err.println("Unable to capture screenshot...");
ex.printStackTrace();
}
}
}
The bit you will probably be most interested in is the method called onTestFailure. This is the part that will be triggered when a test fails. I have a driver factory that provides my access to my driver object, the call to getDriver is getting my driver object from the factory. If you have just got a statically defined driver object you can probably ignore the line:
WebDriver driver = getDriver();
The other methods are just convenience methods to create a file and write the screenshot to it. You'll obviously need to tweak this a bit to allow it to take the location that the screenshot has been written and pass it into your reported log.
I would suggest giving the listener access to your Reporter object and changing:
System.out.println("Written screenshot to " + screenshotAbsolutePath);
to:
Reporter.log("<a href=\"" + screenshotAbsolutePath + "\"><p align=\"left\">Add New PR screenshot at " + new Date()+ "</p>");
In the code above, the directory that the screenshots are saved into is set using a system property called "screenshotDirectory". You will either need to set his system property, or change the following line to a hard coded location where you would like to save your screenshots. To do that this line:
String screenshotDirectory = System.getProperty("screenshotDirectory");
Will need to change to something like:
String screenshotDirectory = "/tmp/screenshots";
or if you use windows, something like:
String screenshotDirectory = "C:\\tmp\\screenshots";

datatore.put() not adding to db?

I have a servelet which can take a request from either a rest service or from a jsp form post that will both call a internal method (internalAddPodcast()) to add an entity to the datastore.
When I hit the internalAddPodcast() from the jsp page, it works fine, I can see the that the entity has been added successfully by querying for it right after adding. BUT when I do it from the rest method addPodcast() the datastore.put() doesn't seem to be actually adding to the datastore, because I try and retreive it right after put() and nothing is coming back. Look down near the bottom of this class where I put the comment "//THIS QUERY IS EMPTY WHEN ADDED FROM THE REST SERVICE :(" That is where I expect to have some results come back, especially the entity that I just put in the data store.
package com.aol.sharepodder;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
#Path("/add/podcast/")
public class AddPodcastServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = Logger.getLogger(AddPodcastServlet.class
.getName());
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String email = req.getParameter("email");
String collectionName = req.getParameter("collectionName");
String podcast_url = req.getParameter("podcast_url");
String podcast_description = req.getParameter("podcast_description");
String podcast_title = req.getParameter("podcast_title");
log.info("--post adding " + collectionName);
internalAddPodcast(email, collectionName, podcast_url,
podcast_description, podcast_title);
resp.sendRedirect("/collection_details.jsp?collectionName="
+ collectionName + "&email=" + email);
}
#POST
#Produces("text/plain")
#Consumes("application/x-www-form-urlencoded")
public String addPodcast(
#DefaultValue("barrand#gmail.com") #FormParam("email") String email,
#DefaultValue("default") #FormParam("collectionName") String collectionName,
#DefaultValue("") #FormParam("podcast_url") String podcast_url,
#DefaultValue("") #FormParam("podcast_description") String podcast_description,
#DefaultValue("") #FormParam("podcast_title") String podcast_title) {
try {
internalAddPodcast(email, collectionName, podcast_url,
podcast_description, podcast_title);
if (podcast_url == "") {
return "No url supplied";
}
return "true";
} catch (Exception e) {
return e.getMessage();
}
}
private void internalAddPodcast(String email, String collectionName,
String podcast_url, String podcast_description, String podcast_title) {
log.info("--INTERNAL ADD ");
log.info("--email " + email);
log.info("--collectionName " + collectionName);
log.info("--podcast_url " + podcast_url);
log.info("--podcast_description " + podcast_description);
log.info("--podcast_title " + podcast_title);
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
Entity podcast = new Entity("Podcast");
podcast.setProperty("collectionName", collectionName);
podcast.setProperty("user", user);
podcast.setProperty("email", email);
Date date = new Date();
podcast.setProperty("date", date);
podcast.setProperty("podcast_title", podcast_title);
podcast.setProperty("podcast_description", podcast_description);
podcast.setProperty("podcast_url", podcast_url);
DatastoreService datastore = DatastoreServiceFactory
.getDatastoreService();
datastore.put(podcast);
//try to log the podcast that I just got done adding to the datastore
Query query = new Query("Podcast");
PreparedQuery pq = datastore.prepare(query);
//THIS QUERY IS EMPTY WHEN ADDED FROM THE REST SERVICE :(
for (Entity p : pq.asIterable()) {
log.info("_loop " + " - " + KeyFactory.keyToString(p.getKey())
+ " -- " + p.getProperty("podcast_title") + " - "
+ p.getProperty("podcast_url"));
}
}
}
Any ideas what I'm doing wrong, and why the entity I'm trying to add from the rest method isn't getting added to the data store.
I know that in both cases, (either from the jsp post, or the rest service) when I get to the internalAddPodcast() all the method params are coming in correctly.
The High Replication datastore is eventually consistent. That means that most queries are not guaranteed to reflect changes that have just been made to the datastore - including returning records you just inserted. Read more about this and how to do strongly consistent queries here.
Ah HA! I found it. I wasn't logging the exception that was being thrown. Basically I was trying to store a string property that was more than 500 characters and it was throwing an exception that I needed to pay attention to :) So it was never getting to the datastore.put()

Problem sending email with image attachment from app engine using java mail api

First of all,I would like to thank everyone for the answers posted.This site is great.
Second of all, I am having a problem and after searching a few days I still can't figure it out.I found a lot of people with the same problem, but no answer.
I am trying to upload an image to a application running on app engine and to send an email with the image as an attachment. I am also using org.apache.commons.fileupload to upload the image.
I successfully sent the email, but I am having trouble with the attachment.
My html form looks like this:
<form id="contact" action="/sign" method="post" enctype="multipart/form-data">
<fieldset>
<label>Nume / Prenume</label>
<input type="text" name="nume" />
<label>Telefon</label>
<input type="text" name="telefon" />
<label>E-mail</label>
<input type="text" name="email"/>
</fieldset>
<fieldset>
<label>Textul sesizarii</label>
<textarea name="textulses"></textarea>
<div class="upload-fix-wrap">
<input size="35" class="upload" type="file" name=myFile />
<input type="text" />
<button>Incarca poze</button>
</div>
<button class="send" type="submit">Trimite </button>
</fieldset>
</form>
My web.xml file where I choose wich servlet should answer looks like this:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>sign</servlet-name>
<servlet-class>com.campiacareiului.CampiaCareiuluiServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sign</servlet-name>
<url-pattern>/sign</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
So, by now I have a html form and a servlet to respond.
First, I tried by using javax.mail:
public class CampiaCareiuluiServlet extends HttpServlet {
private String nume=null;
private String telefon=null;
private String email=null;
private String textulses=null;
private String attname=null;
private byte[] buffer = new byte[8192000];
private boolean att=false;
private int size=0;
private static final Logger log =
Logger.getLogger(CampiaCareiuluiServlet.class.getName());
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
ServletFileUpload upload=new ServletFileUpload();
FileItemIterator it = upload.getItemIterator(req);
while(it.hasNext()){
FileItemStream item = it.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
if(name.equals("nume")) nume=Streams.asString(stream);
else if(name.equals("telefon")) telefon=Streams.asString(stream);
else if(name.equals("email")) email=Streams.asString(stream);
else if(name.equals("textulses")) textulses=Streams.asString(stream);
} else {
att=true;
attname=item.getName();
int len;
size=0;
while ((len = stream.read(buffer, 0, buffer.length)) != -1){
size+=len;
}
}
}
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
String msgBody = "Nume/Prenume: "+nume+" Telefon: "+telefon+" Mail:"+email+"Textul Sesizarii: "+textulses;
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("myAdministratorAccount#gmail.com", ""));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress("aUser#yahoo.com", "Mr. User"));
msg.setSubject("Mail Sesizare Campia Careiului");
msg.setText(msgBody);
if(att){
byte[] bufferTemp = new byte[size];
for(int i=0;i<=size;i++)
bufferTemp[i]=buffer[i];
Multipart mp=new MimeMultipart();
MimeBodyPart attachment= new MimeBodyPart();
DataSource src = new ByteArrayDataSource
(bufferTemp,"image/jpeg");
attachment.setFileName(attname);
attachment.setContent(src,"image/jpeg");
mp.addBodyPart(attachment);
msg.setContent(mp);
}
Transport.send(msg);
resp.sendRedirect("/contact.html");
} catch (Exception ex) {
try {
throw new ServletException(ex);
} catch (ServletException e) {
e.printStackTrace();
}
}
}
}
When I debugged the application it showed that it had uploaded the image to the buffer, but it failed sending the mail (no exception was thrown) .( I uploaded the app to app engine because you cannot send an email if you are running the application locally).
Next I tried using the low level api. The changes I made were:
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
String msgBody = "Nume/Prenume: "+nume+" Telefon: "+telefon+" Mail: "+email+" Textul Sesizarii: "+textulses;
MailService service = MailServiceFactory.getMailService();
MailService.Message msg = new MailService.Message();
msg.setSender("myAdminAccount#gmail.com");
msg.setTo("aUser#yahoo.com");
msg.setSubject("Mail Sesizare Campia Careiului");
msg.setTextBody(msgBody);
if(att){
byte[] bufferTemp = new byte[size];
for(int i=0;i<=size;i++)
bufferTemp[i]=buffer[i];
MailService.Attachment attachment=new MailService.Attachment("picture.pdf",
bufferTemp);
msg.setAttachments(attachment);
}
service.send(msg);
resp.sendRedirect("/contact.html");
Now, it sends the email, with the attachment, but when I try to download the attachment from my email account(either a pdf or a image) it doesn't recognize it.It just says that the file may have been corrupted. When I tried to send an image I put "image/jpeg" and when I tried to send a pdf I put "application/pdf".
I searched everywhere and I found other people with this problem but no solution. If someone could help me I would be grateful. ( I apologize for my spelling errors)
My imports are:
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.activation.DataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import javax.mail.Multipart;
import javax.servlet.http.*;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.apache.commons.io.IOUtils;
import com.google.appengine.api.mail.MailService;
import com.google.appengine.api.mail.MailServiceFactory;
I successfully sent the email with the attachment with the below code.But my problem is that when I try to download the attachment, or when I try to view it, it says that it is corrupted and it doesn't recognize it. I think that the problem lies in uploading the image. To upload the image I use org.apache.commons.fileupload.
Here I upload the image to a byte array:
while ((len = stream.read(buffer, 0, buffer.length)) != -1)
{
size+=len;
}
I also track the size of the uploaded image in "size"
Here, I move the image in another buffer of apropriate dimensions:
byte[] bufferTemp = new byte[size];
for(int i=0;i<size;i++)
bufferTemp[i]=buffer[i];
The image from the attachment has the same dimension as the one uploaded, but is corrupted somehow.If anyone can help. The source code is:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import javax.mail.Multipart;
import javax.servlet.http.*;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
#SuppressWarnings("serial")
public class CampiaCareiuluiServlet extends HttpServlet {
private String nume=null;
private String telefon=null;
private String email=null;
private String textulses=null;
private String attname=null;
private byte[] buffer = new byte[8192000];
private boolean att=false;
private int size=0;
private static final Logger log =
Logger.getLogger(CampiaCareiuluiServlet.class.getName());
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
ServletFileUpload upload=new ServletFileUpload();
FileItemIterator it = upload.getItemIterator(req);
while(it.hasNext()){
FileItemStream item = it.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
if(name.equals("nume")) nume=Streams.asString(stream);
else if(name.equals("telefon")) telefon=Streams.asString(stream);
else if(name.equals("email")) email=Streams.asString(stream);
else if(name.equals("textulses")) textulses=Streams.asString(stream);
} else {
att=true;
attname=item.getName();
int len;
size=0;
while ((len = stream.read(buffer, 0, buffer.length)) != -1){
size+=len;
}
}
}
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
String msgBody = "Nume/Prenume: "+nume+" Telefon: "+telefon+" Mail: "+email+" Textul Sesizarii: "+textulses;
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("ursu.adrian88#gmail.com", "gmail.com Adrian Ursu"));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress("ursu.adrian88#gmail.com", "Mr. User"));
msg.setSubject("Mail Sesizare Campia Careiului");
if(!att){
msg.setText(msgBody);
}
else{
byte[] bufferTemp = new byte[size];
for(int i=0;i<size;i++)
bufferTemp[i]=buffer[i];
Multipart mp=new MimeMultipart();
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(msgBody, "text/plain");
mp.addBodyPart(textPart);
MimeBodyPart attachment= new MimeBodyPart();
DataSource src = new ByteArrayDataSource
(bufferTemp, "image/jpeg");
attachment.setFileName(attname);
attachment.setDataHandler(new DataHandler
(src));
mp.addBodyPart(attachment);
msg.setContent(mp);
msg.saveChanges();
}
Transport.send(msg);
resp.sendRedirect("/contact.html");
} catch (Exception ex) {
try {
throw new ServletException(ex);
} catch (ServletException e) {
e.printStackTrace();
}
}
}
}
I think the problem in example #1 may be that you are setting a text body and then trying to add a multipart. That isn't correct. A message can be of Content-Type: text/plain or Content-Type: multipart/mixed but not both. If there is an attachment, you need to add the text body as one of the multiparts. Something like this (untested):
if (!att) {
msg.setText(msgBody);
} else {
//first build and add the text part
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(msgBody, "text/plain");
Multipart mp=new MimeMultipart();
mp.addBodyPart(textPart));
//now read/buffer the image data (?)
byte[] bufferTemp = new byte[size];
for(int i=0;i<=size;i++)
bufferTemp[i]=buffer[i];
// YOU NEED TO FIX THIS!!
}
// now add the attachment part.
// the attachment data must be added all together, not in pieces
MimeBodyPart attachment= new MimeBodyPart();
// YOU NEED TO FIX THIS!!
attachment.setFileName(attname);
attachment.setContent(bufferTemp,"image/jpeg");
mp.addBodyPart(attachment);
msg.setContent(mp);
There is also a problem with the way you are reading in your image data but you haven't provided enough of your code for me to tell you how to correct it. You'll need to read the ENTIRE image data into some object (array, buffer, etc) before adding it into the body part content. And you can't add src as the content for attachment - you have to use the actual data - either a String or a byte[] etc.
To help understand the concept of body parts, try and visualize the structure of the message. The email headers list a header of Content-type: multipart/mixed, with enclosed parts of Content-type: text/plain and Content-type: image/jpeg.
To: testuser#test.com
From: testuser2#test.com
Date: Aug 19, 2011
Content-Type: multipart/mixed; boundary="aswevb323f23f3f"
This is a message with multiple parts in MIME format.
--aswevb323f23f3f
Content-Type: text/plain
This is the body of the message.
--aswevb323f23f3f
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
ZQs0bWw+CiAgPGhlYWQ+CiAgP49oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
Ym9keSBvZiB0aGUgbWVzc2FnZa48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==
--aswevb323f23f3f
I finally got it to work. the problem (of course) uploading the image. I was overwriting the same bytes in buffer, I didn't take the offset into account. The right way is:
int len=0;
size=0;
while ((len = stream.read(buffer, size,buffer.length)) != -1)
{
size+=len;
}

Resources