B4A Library New Net library - Android FTP, SMTP and POP3

Status
Not open for further replies.
The Net library supports FTP, SMTP and POP3 protocols. This library replaces the FTP library. Both regular connections and SSL connections are supported.
SMTP - Allows to directly connect to SMTP mail servers and send mails, including Html messages and attachments.
POP3 - Allows to directly connect to POP3 mail servers and download messages. Currently the messages are not parsed. The raw string is returned. You can use MailParser class to parse the raw messages.

Installation instructions:
- Download the attach file.
- Copy Net.xml and Net.jar to the additional libraries folder. Make sure that there are no older copies in the internal libraries folder.

V1.81 - latest version
V1.80 - SMTP, POP and FTP can be configured to use a custom trust manager. This allows accepting invalid certificates.

V1.77 - New Sender.MailFrom field. Allows setting the mail address that is sent with the MAIL command. By default it is the same as the Username field.

V1.75 - Adds a configurable timeout parameter - FTP.TimeoutMs. Default timeout is set to 60000 (60 seconds).

V1.70 - Adds support for calling with Wait For: https://www.b4x.com/android/forum/threads/b4x-net-library-ftp-smtp-pop-with-wait-for.84821/
SMTP.AdditionalHeaders map. Allows adding headers to the messages.

V1.63 - Fixes an issue with SMTP mails with attachments. The closing boundary was previously missing.
V1.62 - Fixes an issue with SMTP in StartTLS mode.
V1.61 - Fixes an issue in SMTP related to the content encoding not being set in multipart messages.

V1.60 - New method: FTP.AppendFile. Similar to UploadFile. Appends the data to an existing file if such exists. It sends the APPE FTP command.

V1.53 - Fixes an issue with FTP.CloseNow and SSL connections.

V1.52 - Adds support for different types of authentication methods (SMTP): http://www.b4x.com/android/forum/th...d-ftp-smtp-and-pop3.10892/page-11#post-232432

V1.51 is released. Fixes an issue with FTP over SSL explicit mode.

V1.50 is released. See this link: http://www.b4x.com/android/forum/th...d-ftp-smtp-and-pop3.10892/page-10#post-231145

V1.37 is released. This version removes the automatic escaping of '=' characters in SMTP messages. To implement it in your code you should write:
B4X:
SMTP.Body = SMTP.Body.Replace("=", "=3D")


V1.35 is released. This version adds support for STARTTLS mode.
Unlike UseSSL mode the connection is "upgraded" to a secured connection only after the client sends the STARTTLS command.
Most of the popular smtp servers support this mode, usually on port 587.

B4X:
Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      smtpClient.Initialize("smtp.gmail.com", 587, "[email protected]", "yyy", "SmtpClient")
      smtpClient.StartTLSMode = True
   End If
End Sub
 

Attachments

  • Net.zip
    189.1 KB · Views: 3,003
Last edited:

Harris

Expert
Licensed User
Longtime User
Here is a copy of my code - whenever one has a chance to review. The MessageSent event has been moved to an activity module to capture event.
SMTP params were derived from a Map file (created in my setup)

Thanks

Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.


Dim SMTP1 As SMTP


Dim myserver, myadd, mypass, myto1, myto2, myto3 As String
Dim myport As Int
Dim myssl,wassent As Boolean



End Sub


Sub QueMail
Dim C1 As Cursor
Dim i As Int

' que up out going mail

C1 = DefCM.SQL1.ExecQuery2( "SELECT * FROM Inspections WHERE Sent = ?", Array As String(0) )
If C1.RowCount > 0 Then

SendSetup ' setup the SMTP object for sending
For i = 0 To c1.RowCount - 1
c1.Position = i
wassent = False
' open send session
Dim Recno As Long
Dim Name, From As String
Dim buf() As Byte

Buf = C1.GetBlob("Inspect")
Recno = c1.GetLong("ID_Date")
Name = c1.GetString("Name")
From = " "
From = From &c1.GetString("Trip")&" For: "
From = From &c1.GetString("Driver")&" Truck: "
From = From &c1.GetString("Truck")&" Trailer: "
From = From &c1.GetString("Trailer")



Dim out As OutputStream
out = File.OpenOutput( File.DirDefaultExternal&"/InspForms/",Name, False)
out.WriteBytes(buf,0,buf.Length )
out.Flush
out.Close
Log(" Write pdf to disk for sending: "&Name)
DoEvents

If SendFile(Name, From) = True Then
If wassent Then
Log(" Mail WAS Sent: "&Name)
UpDateSent(Recno)
Else
Log(" Mail WAS NOT Sent: "&Name)
End If
End If

'File.Delete(File.DirDefaultExternal&"/InspForms/",Name)
Next
Else
ToastMessageShow(" No Reports to Send Were Found",True)
End If
C1.Close

End Sub


Sub SendFile(Name As String, From As String) As Boolean

SMTP1.To.Add(myto1)
If myto2.Length > 0 Then
SMTP1.CC.Add(myto2)
End If
If myto3.Length > 0 Then
SMTP1.CC.Add(myto3)
End If
' SMTP1.HtmlBody = False
SMTP1.Subject = "MySite.com: "&Name
SMTP1.Body = From&CRLF&CRLF&CRLF&" ***COPYRIGHT*** "&CRLF&" MYSITE.COM "&CRLF&" ALL RIGHTS RESERVED "
SMTP1.AddAttachment(File.DirDefaultExternal&"/InspForms/",Name)
SMTP1.Send

Log("Attempted to Send May Have Failed: ")

DoEvents
Return True
End Sub



' MOVED TO ACTIVITY MODULE
'Sub SMTP1_MessageSent(Success As Boolean)
'
'Log (" Message Sent: "&Success)
'If Success Then
' wassent = True
'Else
' wassent = False
' Log("Send Error: "&LastException.Message)
'End If
'
'
'End Sub



Sub UpDateSent(rec As Long)

Defcm.SQL1.ExecNonQuery2("UPDATE Inspections SET Sent = ? WHERE ID_Date = ?", Array As String(DateTime.Now,rec))

End Sub

Sub SendSetup
' setup the SMTP object
Dim mp As Map


mp.Initialize
If File.Exists(File.DirDefaultExternal,"smtp.map") Then
mp = File.ReadMap(File.DirDefaultExternal,"smtp.map")
Else
ToastMessageShow(" SMTP Setup File Not Found",False)
End If

myServer = mp.Get("smtpserver")
myadd = mp.Get("smptname")
mypass = mp.Get("smtppass")
myport = mp.Get("smtpport")
myssl = mp.Get("cbsmtpssl")

myto1 = mp.Get("to1")
myto2 = mp.Get("to2")
myto3 = mp.Get("to3")

SMTP1.Initialize(myServer,myport,myadd,mypass,"SMTP1")
SMTP1.UseSSL=True

Msgbox(" SMTP: "&myServer&" "&myadd&" "&mypass&" "&myport&" "&myssl&" Send To: "&myto1," SMTP ")


End Sub
 

Harris

Expert
Licensed User
Longtime User
Sorry vb, DefCM is my default code module - where SQL1 is inited.

The globals contain SMTP1 and user password for priming SMTP1.Intialize.

Funny, I had it all working - sending my pdfs like clockwork then - server responds with Authentication Required....

I setup outlook with the same user and password and get the same result. Must be something with my username and password for that test account.
My tester set my app up with a different account and gets the same return result - no sending

I created a little stub, based on code above and can't seem to get passed it. Time to install 1.8 and then work beyond this.

I will setup a new google email account and see how that flies.

Thanks
 

Harris

Expert
Licensed User
Longtime User
I have it working with my own personal account such as: [email protected].

However, I ask my friend who was having issue with the same test app to use my account. He didn't get anywhere... The MessageSent event error he gets on his Galaxy S2 is:
java.net.ConnectionException: localhost/::1:465 - Connection refused.

LocalHost??? wtf?

This is the same he will get using any of his valid email accounts with gmail.

When i try to use another valid gmail account (which worked when I first tried SMTP), I get:
Send Error: java.lang.RuntimeException: Empty writer returned: 530-5.5.1 Authentication Required. Learn more at mail.google.....

I will post my complete test app code to see if anyone else sees the same.

Thanks
 

Harris

Expert
Licensed User
Longtime User
Attached is a simple sample of the test smtp.

My primary account works, were as many other accounts produce erros in the connection.

Thanks
 

Attachments

  • testsmtp.zip
    10 KB · Views: 454

vb1992

Well-Known Member
Licensed User
Longtime User
what happens when you test the basics out?

B4X:
Sub Process_Globals
    Dim SMTP As SMTP
End Sub
Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        SMTP.Initialize("smtp.gmail.com", 465, "[email protected]", "XXX", "SMTP")
        SMTP.UseSSL = True 'Gmail requires SSL.
    End If
    SMTP.To.Add("[email protected]")
    SMTP.Subject = "This is the subject"
    SMTP.Body = "This is the message body."
    'SMTP.AddAttachment(File.DirRootExternal, "somefile")
    SMTP.Send
End Sub
Sub SMTP_MessageSent(Success As Boolean)
    Log(Success)
    If Success Then
        ToastMessageShow("Message sent successfully", True)
    Else
        ToastMessageShow("Error sending message", True)
        Log(LastException.Message)
    End If
End Sub



Have you read up on the PORTS?

Ports
Server administrators choose whether clients use TCP port 25 (SMTP) or port 587 (Submission), as formalized in RFC 6409, for relaying outbound mail to a mail server. The specifications and many servers support both. Although some servers support port 465 for legacy secure SMTP in violation of the specifications, it is preferable to use standard ports and standard ESMTP commands[14] according to RFC 3207 if a secure session needs to be used between the client and the server.
Some servers are set up to reject all relaying on port 25, but valid users authenticating on port 587 are allowed to relay mail to any valid address.
Some Internet service providers intercept port 25, redirecting traffic to their own SMTP server regardless of the destination address. This means that it is not possible for their users to access an SMTP server outside the ISP's network using port 25.
Some SMTP servers support authenticated access on an additional port other than 25 to allow users to connect to them even if port 25 is blocked.
 
Last edited:

Harris

Expert
Licensed User
Longtime User
Local host issue solved:
Seems the hint color is very close to a valid input color on some devices - and possibly the age of ones eyes plays a role. My tester did not supply a server value because the hint said: smpt.gmail.com My bad.. never supply valid values as hints.... :sign0013:

As for my other valid address to the same gmail server, I will try your basic code above. You saw my test app is not far from your code above?

Also, it would be nice to associate a send request with an ID. That way, I could determine which mail actually "made it" and which ones failed. With the ID, I could then update my tables record with the Sent flag and delete the file I extracted from my blob. Testing with the S2 this am, the mail was received long before (about 2 minutes) the ack came back from the server (Success) saying it was sent. This was due to low signal strength (I assume). When the same test was tried with phone in the signal booster, Success was received right away.

Any suggestions on how to handle this would be most welcome. I have even tried waiting for the event directly after a send. I don't see the event until I exit the loop however long I wait..

SMTP.Send
do while MsgEvent = False
DoEvents
cnt = cnt + 1
if cnt > 2000 then Exit
loop

In the event, I set MsgEvent to True when it fires, however it never does....

Thanks everyone
 

vb1992

Well-Known Member
Licensed User
Longtime User
As for my other valid address to the same gmail server, I will try your basic code above. You saw my test app is not far from your code above?

I just know that code above works, with my gmail,
so I figured if you can test that other gmail
account with it, we are comparing apples to apples
 

Harris

Expert
Licensed User
Longtime User
My other account now works!
GMail was wanting me to authenticate this account. I only used it for testing on my device so I wasn't aware that it needed me to do this since this account was not listed in my gmail. Now that I have done this, it works fine - no error requesting authenication - as posted above.

Yes, the sample code functions fine. Any suggestions about handling multiple mail send and confirmations?
Thanks
 

Harris

Expert
Licensed User
Longtime User
However the best approach is to wait for one message to be sent and then send the next one in MessageSent event.

So, if I understand this correctly:
I have 10 mails to send, create a list of these mails - que up and send the first one. Wait for response in MessageSent event (update list of pass or fail). In MessageSent, check if more mails need to be sent in list. Repeat... to end of list. When entire list has been processed, update my db table with results from list (mark sent field accordingly) and clean up files on disk (attachments).

Sounds recursive but I think I can handle it.

Thanks
 

Smee

Well-Known Member
Licensed User
Longtime User
I am sending emails ok but the SMTP1_MessageSent(Success As Boolean) sub is not firing. I am using a code module for all routines

does it have to be used in activity mod?
 

Harris

Expert
Licensed User
Longtime User
YES, the event must be in activity module.... That was my problem (among others).

I have SMTP sending multiple mails working now...

I dont think its pretty, but it works

I can update my db when the mail was sent and clean up left over files that were the attachments. Keep a clean house (wish I could say for my own - maid wanted...).
 

Smee

Well-Known Member
Licensed User
Longtime User
I do not know what is wrong but the SMTP1_MessageSent(Success As Boolean) sub is still not firing.

I have putting all the code in the Main Activity Module, Code Module and Service Module.
This is how i send
B4X:
SMTP1.Initialize(server, port, emailname, Password, protocol)
SMTP1.UseSSL=True
SMTP1.To.Add(Receiver)
SMTP1.Subject = Subject
SMTP1.Body = Body
SMTP1.AddAttachment(DirName, FileName)
SMTP1.Send

Sub SMTP1_MessageSent(Success As Boolean)

log( Success )

end sub

i have tried putting the dim smtp1 in process globals and globals all without success
 

Smee

Well-Known Member
Licensed User
Longtime User
:sign0148:

don' t know where i got the protocol from??? I think it was when i looked up Gmail requirements.

Anyway i changed to "SMTP1" and it works beautifully.

Thank you

FWIW to any others, I changed all the code and put it into a Service Module and it runs great in the background. The program keeps running whilst all emails are being silently sent.
 

Harris

Expert
Licensed User
Longtime User
Yes, good idea.
I have accomplished what I wanted and have mine in a code module - "attempting" to send when I return to the main form (as would be normal in my app). However, in a service module, it could attempt always and often until all mails went out. My users have limited connection through tablets and areas not served well by cell coverage. This would ensure it would get out when it could.
I shall convert my app pronto...

Thanks all....
 

cirollo

Active Member
Licensed User
Longtime User
Error using the new net library

I was using the network library
I needed the passivemode property so I used the net 1.20 library deselecting the network library

I'm getting this when compiling

B4X:
Compiling code.                         0.75
Generating R file.                      0.00
Compiling generated Java code.          2.59
Convert byte code - optimized dex.      Error
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lorg/apache/commons/net/DatagramSocketClient;
   at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:123)
   at com.android.dx.dex.file.DexFile.add(DexFile.java:163)
   at com.android.dx.command.dexer.Main.processClass(Main.java:486)
   at com.android.dx.command.dexer.Main.processFileBytes(Main.java:455)
   at com.android.dx.command.dexer.Main.access$400(Main.java:67)
   at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:394)
   at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:245)
   at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:131)
   at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:109)
   at com.android.dx.command.dexer.Main.processOne(Main.java:418)
   at com.android.dx.command.dexer.Main.processAllFiles(Main.java:329)
   at com.android.dx.command.dexer.Main.run(Main.java:206)
   at com.android.dx.command.dexer.Main.main(Main.java:174)
   at com.android.dx.command.Main.main(Main.java:95)
1 error; aborting
   Standard dexer.

why???
 

biometrics

Active Member
Licensed User
Longtime User
Is FTP Resume Supported?

Hi Erel,

Is FTP resume supported? Does the library do it automatically or should I send a resume command first using SendCommand before DownloadFile?
 
Status
Not open for further replies.
Top