cl-smtp-cvs
Threads by month
- ----- 2026 -----
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- 43 discussions
[cl-smtp-cvs] Is Israel a Democracy? -- The problem with intellectually insecure whites -- Should Christians Support Israeli Terrorism in Gaza?
by Lawrence Auster 23 Jan '09
by Lawrence Auster 23 Jan '09
23 Jan '09
The Jewish State of Israel has no constitution, nor does it name its borders. Israel's hidden constitution is Judaism. Israel's undeclared borders range from the Nile to the Euphrates rivers. Israel's desired jurisdiction extends over the entire Earth.
It could not be more clear that the Jewish State follows a foreign policy which obeys Jewish Law as iterated in the Hebrew Bible, the Talmud, Maimonedes, the Cabalah, and the many commentaries and refinements of same. The Jews are genociding the native inhabitants of Palestine, just as their religion advises, and because
their religion teaches them to do so. They treat non-Jews as if non-humans, just as their religion requires them to do. They make perpetual war on every nation on Earth, just as their genocidal Jewish God has instructed.
The Jews of Israel are simply being Jews. Jews are an existential threat to the human race.
Israel contains one third of the Jews of the World. It is not some aberration of the Jewish spirit, but the condensation and concentration of the perverse Jewish mentality, which malady also pervades the remaining two thirds of Jewry, who almost unanimously support the Jewish State, and who certainly do unanimously support
the Jewish People and its consistent and constant crimes against the human race. Israel is Jewry and the danger of Israel is the danger of the Jewish People to all others, as the Jews have demonstrated each and every day of their existence.
The Jews, the entire Jewish People of 15 million, will not relent until they have wiped out all non-Jews in "Greater Israel". They will not stop destroying all other cultures, nations, religions, ethnicities, races, competition, etc. until they are either stopped, or succeed in their ancient quest to destroy the human race.
What Israel is doing is not some reaction to outside forces, nor was the formation of Israel a response to the Holocaust. Israel is simply following the plan laid out in the Jews' religious texts. The Jews have openly planned to take Palestine and genocide the native population of Palestine for some 2,500 years before the
Holocaust. The Jews have openly complained that "anti-Semitism" is a threat that gives them the right to genocide the Palestinians, not merely since the advent of Nazism, but for some 2,500 years.
The Jewish religion is the Constitution of the Jewish State of Israel, and, to a greater or lesser extent, the constitution of the nature of every Jew alive. The borders of Israel are the range the Jew roams over the entire World. The perverse Jewish mentality is inbred by a Jew's exposure to his parents and to his community. Judaism
passes in the spit and slobber of Jewish mother telling her Jewish child that he is a "Jew", as much as Judaism passes in the poison and pain of a Talmudic tractate. The secular Jews did not suddenly come to life after the Enlightenment and the Jewish Reformation a body of vampires that appeared ex nihilo, in vacuo, mostly
atheistical and undetached from formally practiced Judaism. Judaism is the Jew. It is a mindset that transcends and supercedes religion. It is a belief set, a way of life, a perception of one's self and one's relation to the World that makes a Jew, a Jew, and a danger to all of humanity.
In fact, the religious shell of Judaism is like the stretched and infected skin of a lycanthropic pustule. When you lance it to cure the infection, the virus only becomes more contagious and spills directly on the non-Jew.
The secular Jew is a deliberate product of the hyper-religious Jew, a monster created out of the hewed corpses of the fanatically religious Jew, a Golem which is conjured up to enter the World of the non-Jew and poison its blood, and boil its brain with a rabid lunacy that bites and spreads, until the infected community feeds on
itself and fills the fields with rotting bloating bodies, where once human beings tilled the soil and tended to their families. The religious Jew created the secular Jew as an army of Esthers who seduce with open thighs, broad smiles, and a Siren call that lures in the non-Jew to cast his skull upon the jagged rocks and color the seas
with his blood, sickened and blinded by the venereal disease of Judaism in secular form.
Israel is not a secular democracy. It is a religious mockery. It is a rabid bat flying to the ends of the Earth, to end the Earth. No one will be free nor safe until the disease is quarantined and dies out.
Source: http://www.ziopedia.org/articles/israel/how_can_israel_claim_to_be_a_%27dem…
--------------------
The problem with intellectually insecure whites
By Kevin MacDonald
January 19, 2009
America will soon have a white minority. This is a much desired state of affairs for the hostile elites who hold political power and shape public opinion. But it certainly creates some management issues � at least in the long run. After all, it�s difficult to come up with an historical example of a nation with a solid ethnic majority (90%
white in 1950) that has voluntarily decided to cede political and cultural power. Such transformations are typically accomplished by military invasions, great battles, and untold suffering.
And it�s not as if everyone is doing it. Only Western nations view their own demographic and cultural eclipse as a moral imperative. Indeed, as I have noted previously, it is striking that racial nationalism has triumphed in Israel at the same time that the Jewish intellectual and political movements and the organized Jewish
community have been the most active and effective force for a non-white America. Indeed, a poll in 2008 found that Avigdor Lieberman was the second most popular politician in Israel. Lieberman has advocated expulsion of Arabs from Israel and has declared himself a follower of Vladimir Jabotinsky, the leading pioneer of racial
Zionism. The most popular politician in the poll was Benjamin Netanyahu � another admirer of Jabotinsky. Prime Minister Ehud Olmert and Foreign Minister Tzipi Livni are also Jabotinskyists.
The racial Zionists are now carrying out yet another orgy of mass murder after a starvation-inducing blockade and the usual triggering assault designed to provoke Palestinian retaliation � which then becomes the cover for claims that Israel is merely defending itself against terrorism. This monstrosity was approved by
overwhelming majorities of both Houses of Congress. The craven Bush administration did its part by abstaining from a UN resolution designed by the US Secretary of State as a result of a personal appeal by the Israeli Prime Minister. This is yet another accomplishment of the Israel Lobby, but one they would rather not have
discussed in public. People might get the impression that the Lobby really does dictate US foreign policy in the Mideast. Obviously, such thoughts are only entertained by anti-Semites.
But I digress.
In managing the eclipse of white America, one strategy of the mainstream media is to simply ignore the issue. Christopher Donovan (�For the media, the less whites think about their coming minority status, the better�) has noted that the media, and in particular, the New York Times, are quite uninterested in doing stories that
discuss what white people think about this state of affairs.
It�s not surprising that the New York Times � the Jewish-owned flagship of anti-white, pro-multicultural media � ignores the issue. The issue is also missing from so-called conservative media even though one would think that conservatives would find the eclipse of white America to be an important issue. Certainly, their audiences
would find it interesting.
Now we have an article �The End of White America� written by Hua Hsu, an Assistant Professor of English at Vassar College. The article is a rather depressing display of what passes for intellectual discourse on the most important question confronting white people in America.
Hsu begins by quoting a passage in F. Scott Fitzgerald�s The Great Gatsby in which a character, Tom Buchanan, states: �Have you read The Rise of the Colored Empires by this man Goddard?� � Well, it�s a fine book, and everybody ought to read it. The idea is if we don�t look out the white race will be�will be utterly submerged.
It�s all scientific stuff; it�s been proved.�
Buchanan�s comment is a thinly veiled reference to Lothrop Stoddard�s The Rising Tide of Color which Hsu describes as �rationalized hatred� presented in a scholarly, gentlemanly, and scientific tone. (This wording that will certainly help him when he comes up for tenure.) As Hsu notes, Stoddard had a doctorate from Harvard
and was a member of many academic associations. His book was published by a major publisher. It was therefore �precisely the kind of book that a 1920s man of Buchanan�s profile � wealthy, Ivy League�educated, at once pretentious and intellectually insecure � might have been expected to bring up in casual conversation.�
Let�s ponder that a bit. The simple reality is that in the year 2009 an Ivy League-educated person, "at once pretentious and intellectually insecure," would just as glibly assert the same sort of nonsense as Hsu. To wit:
The coming white minority does not mean that the racial hierarchy of American culture will suddenly become inverted, as in 1995�s White Man�s Burden, an awful thought experiment of a film, starring John Travolta, that envisions an upside-down world in which whites are subjugated to their high-class black oppressors. There will
be dislocations and resentments along the way, but the demographic shifts of the next 40 years are likely to reduce the power of racial hierarchies over everyone�s lives, producing a culture that�s more likely than any before to treat its inhabitants as individuals, rather than members of a caste or identity group.
The fact is that no one can say for certain what multicultural America without a white majority will be like. There is no scientific or historical basis for claims like �the demographic shifts of the next 40 years are likely to reduce the power of racial hierarchies over everyone�s lives, producing a culture that�s more likely than any before
to treat its inhabitants as individuals, rather than members of a caste or identity group.�
Indeed, there is no evidence at all that we are proceeding to a color blind future. The election results continue to show that white people are coalescing in the Republican Party, while the Democrats are increasingly the party of a non-white soon-to-be majority.
Is it so hard to believe that when this coalition achieves a majority that it will further compromise the interests of whites far beyond contemporary concerns such as immigration policy and affirmative action? Hsu anticipates a colorblind world, but affirmative action means that blacks and other minorities are certainly not treated as
individuals. And it means that whites � especially white males � are losing out on opportunities they would have had without these policies and without the massive non-white immigration of the last few decades.
Given the intractability of changing intelligence and other traits required for success in the contemporary economy, it is unlikely that 40 more years of affirmative action will attain the outcomes desired by the minority lobbies. Indeed, in Obama's America, blacks are rioting in Oakland over perceived racial injustices, and from 2002
�2007, black juvenile homicide victims increased 31%, while black juvenile homicide perpetrators increased 43%. Hence, the reasonable outlook is for a continuing need for affirmative action and for racial activism in these groups, even after whites become a minority.
Whites will also lose out because of large-scale importation of relatively talented immigrants from East Asia. Indeed, as I noted over a decade ago, "The United States is well on the road to being dominated by an Asian technocratic elite and a Jewish business, professional, and media elite."
Hsu shows that there already is considerable anxiety among whites about the future. An advertizing executive says, �I think white people feel like they�re under siege right now � like it�s not okay to be white right now, especially if you�re a white male. ... People are stressed out about it. �We used to be in control! We�re losing
control�� Another says, "There�s a lot of fear and a lot of resentment."
It's hard to see why these feelings won't increase in the future.
A huge problem for white people is lack of intellectual and cultural confidence. Hsu quotes Christian (Stuff White People Like) Lander saying, "I get it: as a straight white male, I�m the worst thing on Earth." A professor comments that for his students "to be white is to be culturally broke. The classic thing white students say when
you ask them to talk about who they are is, �I don�t have a culture.� They might be privileged, they might be loaded socioeconomically, but they feel bankrupt when it comes to culture � They feel disadvantaged, and they feel marginalized."
This lack of cultural confidence is no accident. For nearly 100 years whites have been subjected to a culture of critique emanating from the most prestigious academic and media institutions. And, as Hsu points out, the most vibrant and influential aspect of American popular culture is hip-hop�a product of the African American
urban culture.
The only significant group of white people with any cultural confidence centers itself around country music, NASCAR, and the small town values of traditional white America. For this group of whites � and only this group � there is "a racial pride that dares not speak its name, and that defines itself through cultural cues instead�a
suspicion of intellectual elites and city dwellers, a preference for folksiness and plainness of speech (whether real or feigned), and the association of a working-class white minority with 'the real America.'�
This is what I term implicit whiteness � implicit because explicit assertions of white identity have been banned by the anti-white elites that dominate our politics and culture. It is a culture that, as Hsu notes, "cannot speak its name."
But that implies that the submerged white identity of the white working class and the lack of cultural confidence exhibited by the rest of white America are imposed from outside. Although there may well be characteristics of whites that facilitate this process, this suppression of white identity and interests is certainly not the natural
outcome of modernization or any other force internal to whites as a people. In my opinion, it is the result of the successful erection of a culture of critique in the West dominated by Jewish intellectual and political movements.
The result is that educated, intellectually insecure white people these days are far more likely to believe in the utopian future described by Hsu than in hard and cautious thinking about what the future might have in store for them.
It's worth dwelling a bit on the intellectual insecurity of the whites who mindlessly utter the mantras of multiculturalism that they have soaked up from the school system and from the media. Most people do not have much confidence in their intellectual ability and look to elite opinion to shape their beliefs. As I noted elsewhere,
A critical component of the success of the culture of critique is that it achieved control of the most prestigious and influential institutions of the West, and it became a consensus among the elites, Jewish and non-Jewish alike. Once this happened, it is not surprising that this culture became widely accepted among people of very
different levels of education and among people of different social classes.
Most people are quite insecure about their intellectual ability. But they know that the professors at Harvard, and the editorial page of the New York Times and the Washington Post, and even conservative commentators like Rush Limbaugh and Sean Hannity are all on page when it comes to racial and ethnic issues. This is a
formidable array, to the point that you almost have to be a crank to dissent from this consensus.
I think one of the greatest triumphs of the left has been to get people to believe that people who assert white identity and interests or who make unflattering portrayals of organized Jewish movements are morally degenerate, stupid, and perhaps psychiatrically disturbed. Obviously, all of these adjectives designate low status.
The reality is that the multicultural emperor has no clothes and, because of its support for racial Zionism and the racialism of ethnic minorities in America, it is massively hypocritical to boot. The New York Times, the academic left, and the faux conservatives that dominate elite discourse on race and ethnicity are intellectually
bankrupt and can only remain in power by ruthlessly suppressing or ignoring the scientific findings.
This is particularly a problem for college-educated whites. Like Fitzgerald's Tom Buchanan, such people have a strong need to feel that their ideas are respectable and part of the mainstream. But the respectable mainstream gives them absolutely nothing with which to validate themselves except perhaps the idea that the world
will be a better place when people like them no longer have power. Hsu quotes the pathetic Christian Lander: "�Like, I�m aware of all the horrible crimes that my demographic has done in the world. ... And there�s a bunch of white people who are desperate � desperate � to say, �You know what? My skin�s white, but I�m not one
of the white people who�s destroying the world.��
As a zombie leftist during the 1960s and 1970s, I know what that feeling of desperation is like � what it's like to be a self-hating white. We must get to the point where college-educated whites proudly and confidently say they are white and that they do not want to become a minority in America.
This reminds me of the recent docudrama Milk, which depicts the life of gay activist Harvey Milk. Milk is sure be nominated for an Oscar as Best Picture because it lovingly illustrates a triumph of the cultural left. But is has an important message that should resonate with the millions of whites who have been deprived of their
confidence and their culture: Be explicit. Just as Harvey Milk advocated being openly gay even in the face of dire consequences, whites need to tell their family and their friends that they have an identity as a white person and believe that whites have legitimate interests as white people. They must accept the consequences
when they are harassed, fired from their jobs, or put in prison for such beliefs. They must run for political office as openly pro-white.
Milk shows that homosexuals were fired from their jobs and arrested for congregating in public. Now it's the Southern Poverty Law Center and the rest of the leftist intellectual and political establishment that harasses and attempts to get people fired. But it's the same situation with the roles reversed. No revolution was ever
accomplished without some martyrs. The revolution that restores the legitimacy of white identity and the legitimacy of white interests will be no exception.
But it is a revolution that is absolutely necessary. The white majority is foolish indeed to entrust its future to a utopian hope that racial and ethnic identifications will disappear and that they won�t continue to influence public policy in ways that compromise the interests of whites.
It does not take an overactive imagination to see that coalitions of minority groups could compromise the interests of formerly dominant whites. We already see numerous examples in which coalitions of minority groups attempt to influence public policy, including immigration policy, against the interests of the whites. Placing
ourselves in a position of vulnerability would be extremely risky, given the deep sense of historical grievance fostered by many ethnic activists and organized ethnic lobbies.
This is especially the case with Jews. Jewish organisations have been unanimous in condemning Western societies, Western traditions, and Christianity, for past crimes against Jews. Similar sentiments are typical of a great many African Americans and Latinos, and especially among the ethnic activists from these groups. The
�God damn America� sermon by President Obama's pastor comes to mind as a recent notorious example.
The precedent of the early decades of the Soviet Union should give pause to anyone who believes that surrendering ethnic hegemony does not carry risks. The Bolshevik revolution had a pronounced ethnic angle: To a very great extent, Jews and other non-Russians ruled over the Russian people, with disastrous
consequences for the Russians and other ethnic groups that were not able to become part of the power structure. Jews formed a hostile elite within this power structure � as they will in the future white-minority America; Jews were �Stalin�s willing executioners.�
Two passages from my review of Yuri Slezkine's The Jewish Century seem particularly appropriate here. The first passage reminds me of the many American Jews who adopt a veneer of support for leftist versions of social justice and racial tolerance while nevertheless managing to support racial Zionism and the mass murder,
torture, and incarceration of the Palestinian people in one of the largest prison systems the world has ever seen. Such people may be very different when they become a hostile elite in a white-minority America.
Many of the commentators on Jewish Bolsheviks noted the �transformation� of Jews [after the Bolshevik Revolution]. In the words of [a] Jewish commentator, G. A. Landau, �cruelty, sadism, and violence had seemed alien to a nation so far removed from physical activity.� And another Jewish commentator, Ia. A. Bromberg, noted
that:
the formerly oppressed lover of liberty had turned into a tyrant of �unheard-of-despotic arbitrariness��. The convinced and unconditional opponent of the death penalty not just for political crimes but for the most heinous offenses, who could not, as it were, watch a chicken being killed, has been transformed outwardly into a
leather-clad person with a revolver and, in fact, lost all human likeness. ...
After the Revolution, ... there was active suppression of any remnants of the older order and their descendants. ... The mass murder of peasants and nationalists was combined with the systematic exclusion of the previously existing non-Jewish middle class. The wife of a Leningrad University professor noted, �in all the
institutions, only workers and Israelites are admitted; the life of the intelligentsia is very hard� (p. 243). Even at the end of the 1930s, prior to the Russification that accompanied World War II, �the Russian Federation�was still doing penance for its imperial past while also serving as an example of an ethnicity-free society� (p. 276).
While all other nationalities, including Jews, were allowed and encouraged to keep their ethnic identities, the revolution remained an anti-majoritarian movement.
The difference from the Soviet Union may well be that in white-minority America it will not be workers and Israelites who are favored, but non-whites and Israelites. Whites may dream that they are entering the post-racial utopia imagined by their erstwhile intellectual superiors. But it is quite possible that they are entering into a
racial dystopia of unimaginable cruelty in which whites will be systematically excluded in favor of the new elites recruited from the soon-to-be majority. It's happened before.
Kevin MacDonald is a professor of psychology at California State University�Long Beach.
Permanent URL with hyperlinks:
http://www.theoccidentalobserver.net/articles/MacDonald-Hsu.html
-----------
Should Christians Support Israeli Terrorism in Gaza?
A timely discussion between Rev. Ted Pike and Dr. David Duke, one especially important for the Christians in our audience
http://www.davidduke.com/mp3/dukeradio090122DukeandPikeonGaza.mp3
In this vital discussion, Rev. Pike and Dr. Duke explore the Pro-Israel attitude of some Christian evangelical organizations, and why their position not only goes directly against Christian morality and decency, but actually is directly opposite of that expressed by Christian Scriptures. Today, Many Christians are instructed that Jews
and today�s Israel has a special covenant� with God. In fact, the New Testament in the clearest of language states that the Jews �continued not in my covenant, and I considered them not, saith the Lord.� Here�s the quote that Christians aren�t supposed to notice.:
8:10 Not according to the covenant that I made with their fathers, in the day when I took them by the hand out of the land of Egypt; because they continued not in my covenant, and I regarded them not, saith the Lord. (Hebrews 8:10)
They also don�t seem to notice that a 2000 year old Judaic war against Christianity that has been waged since time of Jesus Christ and still goes on today with the most powerful Jewish organizations attempting to destroy European and American traditions, that has even become a war on our Christmas traditions.
Dr. Duke and Ted Pike also speak about how over a hundred thousand Christian Palestinians have suffered with their families from anti-Christian Israel! Christian support of Israel has resulted in the very birthplace of Jesus Christ, go from 90 percent Palestinian Christians to 35 percent today because of Israeli terror and
occupation. They ask, �How could any Christian in good conscience support the anti-Christian state of Israel, bombing the homes, killing and maiming, torturing and oppressing fellow Christian men, women and children?�
This is a vital show for every Christian reader and listener of DavidDuke.com. Next time, you hear someone say, �God tells us that we must support Israel� you will have the clear Christian answer that just the opposite is true!
For documentation on this be sure to read some of the well-footnoted, sample chapters of Jewish Supremacism and My Awakening.
Source :
http://www.davidduke.com/general/should-christians-support-israeli-terroris…
-------------------------------------
You or someone using your email adress is currently subscribed to the Lawrence Auster
Newletter. If you wish to unsubscribe from our mailing list, please let us know by calling to 1 212 865 1284
Thanks,
Lawrence Auster,
238 W 101 St Apt. 3B
New York, NY 10025
Contact: lawrence.auster(a)att.net
-------------------------------------
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv27009
Modified Files:
CHANGELOG cl-smtp.asd smtp-output-stream.lisp
Log Message:
Fixed stream-element-type. Thanks Attila Lendvai for the bug report.
--- /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2008/04/12 19:40:36 1.13
+++ /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2008/04/17 08:33:55 1.14
@@ -1,3 +1,8 @@
+Version 20080417.1
+2008.04.17
+Fixed stream-element-type. Thanks Attila Lendvai for the bug report.
+Change smtp-output-stream, cl-smtp.asd, CHANGELOG
+
Version 20080412.1
2008.04.12
Fixed TLS directly functionality, switch to ssl stream bevor read from stream.
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2008/04/12 19:40:36 1.15
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2008/04/17 08:33:55 1.16
@@ -17,7 +17,7 @@
;;; Description: cl-smtp ASDF system definition file
(asdf:defsystem :cl-smtp
- :version "20080412.1"
+ :version "20080417.1"
:perform (load-op :after (op webpage)
(pushnew :cl-smtp cl:*features*))
:depends-on (:usocket
--- /project/cl-smtp/cvsroot/cl-smtp/smtp-output-stream.lisp 2008/04/02 18:02:29 1.1
+++ /project/cl-smtp/cvsroot/cl-smtp/smtp-output-stream.lisp 2008/04/17 08:33:55 1.2
@@ -41,7 +41,7 @@
:reader external-format)))
(defmethod stream-element-type ((stream smtp-output-stream))
- (stream-element-type (stream stream)))
+ (stream-element-type (encapsulated-stream stream)))
(defmethod close ((stream smtp-output-stream) &key abort)
(close (encapsulated-stream stream) :abort abort))
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv24371
Modified Files:
CHANGELOG cl-smtp.asd cl-smtp.lisp index.html
Log Message:
Fixed TLS directly functionality, switch to ssl stream bevor read from stream.
--- /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2008/04/03 08:56:33 1.12
+++ /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2008/04/12 19:40:36 1.13
@@ -1,5 +1,10 @@
+Version 20080412.1
+2008.04.12
+Fixed TLS directly functionality, switch to ssl stream bevor read from stream.
+Change cl-smtp.lisp, cl-smtp.asd, CHANGELOG
+
Version 20080402.1
-2007.04.02
+2008.04.02
Added support for sending raw messages. (Hans Huebner)
Fixed STARTTLS so that an EHLO command is sent after STARTTLS. (Hans Huebner)
Changed Authentication functionality, the actual authentication method used is determined by looking at the advertised features of the SMTP server. (Hans Huebner)
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2008/04/03 08:56:33 1.14
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2008/04/12 19:40:36 1.15
@@ -2,7 +2,7 @@
;;; This file is part of CL-SMTP, the Lisp SMTP Client
-;;; Copyright (C) 2004/2005/2006/2007 Jan Idzikowski
+;;; Copyright (C) 2004/2005/2006/2007/2008 Jan Idzikowski
;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the Lisp Lesser General Public License
@@ -17,7 +17,7 @@
;;; Description: cl-smtp ASDF system definition file
(asdf:defsystem :cl-smtp
- :version "20080402.1"
+ :version "20080412.1"
:perform (load-op :after (op webpage)
(pushnew :cl-smtp cl:*features*))
:depends-on (:usocket
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2008/04/02 18:02:29 1.12
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2008/04/12 19:40:36 1.13
@@ -266,12 +266,10 @@
to use further down in the conversation, which may be different from
the original stream if we switched to SSL."
- ;; Read the initial greeting from the SMTP server
- (smtp-command stream nil
- 220)
-
(unless (or ssl authentication)
;; Unless we want ESMTP features, perform classic SMTP handshake and return
+ ;; Read the initial greeting from the SMTP server
+ (smtp-command stream nil 220)
(smtp-command stream (format nil "HELO ~A"
(usocket::get-host-name))
250)
@@ -280,7 +278,10 @@
;; When SSL or authentication requested, perform ESMTP EHLO
(let (features)
(labels
- ((do-ehlo ()
+ ((read-greetings ()
+ ;; Read the initial greeting from the SMTP server
+ (smtp-command stream nil 220))
+ (do-ehlo ()
(setf features (rest (smtp-command stream (format nil "EHLO ~A" local-hostname)
250))))
(convert-connection-to-ssl ()
@@ -299,6 +300,7 @@
:latin-1 :eol-style :lf)))))
(ecase ssl
((or t :starttls)
+ (read-greetings)
(do-ehlo)
(unless (find "STARTTLS" features :test #'equal)
(error "this server does not supports TLS"))
@@ -313,8 +315,10 @@
(:tls
;; Plain SSL connection
(convert-connection-to-ssl)
+ (read-greetings)
(do-ehlo))
((nil)
+ (read-greetings)
(do-ehlo))))
(when authentication
(smtp-authenticate stream authentication features)))
--- /project/cl-smtp/cvsroot/cl-smtp/index.html 2007/11/05 19:58:24 1.1
+++ /project/cl-smtp/cvsroot/cl-smtp/index.html 2008/04/12 19:40:36 1.2
@@ -53,7 +53,8 @@
</tr>
<tr>
<td>CMU CL</td>
- <td class="working">working</td>
+ <td class="broken">working</td>
+ <td>ssl not working </td>
</tr>
<tr>
<td>Lispworks</td>
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv4564
Modified Files:
CHANGELOG cl-smtp.asd
Log Message:
change version number, wrong date
--- /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2008/04/02 18:02:28 1.11
+++ /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2008/04/03 08:56:33 1.12
@@ -1,5 +1,5 @@
-Version 20080202.1
-2007.02.02
+Version 20080402.1
+2007.04.02
Added support for sending raw messages. (Hans Huebner)
Fixed STARTTLS so that an EHLO command is sent after STARTTLS. (Hans Huebner)
Changed Authentication functionality, the actual authentication method used is determined by looking at the advertised features of the SMTP server. (Hans Huebner)
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2008/04/02 18:02:29 1.13
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2008/04/03 08:56:33 1.14
@@ -17,7 +17,7 @@
;;; Description: cl-smtp ASDF system definition file
(asdf:defsystem :cl-smtp
- :version "20080202.1"
+ :version "20080402.1"
:perform (load-op :after (op webpage)
(pushnew :cl-smtp cl:*features*))
:depends-on (:usocket
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv32398
Added Files:
package.lisp
Log Message:
ups sorry, the package.lisp file from Hans Huebners patch
--- /project/cl-smtp/cvsroot/cl-smtp/package.lisp 2008/04/02 19:39:59 NONE
+++ /project/cl-smtp/cvsroot/cl-smtp/package.lisp 2008/04/02 19:39:59 1.1
;;; -*- mode: Lisp -*-
;;; This file is part of CL-SMTP, the Lisp SMTP Client
;;; Copyright (C) 2004/2005/2006/2007 Jan Idzikowski
;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the Lisp Lesser General Public License
;;; (http://opensource.franz.com/preamble.html) known as the LLGPL.
;;; This library is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; Lisp Lesser GNU General Public License for more details.
;;; File: package.lisp
;;; Description: cl-smtp package definition file
(in-package :cl-user)
(defpackage :cl-smtp
(:use :cl :asdf :flexi-streams :trivial-gray-streams)
(:export "SEND-EMAIL"
"WITH-SMTP-MAIL"
"SMTP-ERROR"
"SMTP-PROTOCOL-ERROR"
"NO-SUPPORTED-AUTHENTICATION-METHOD"
"RCPT-FAILED"
"IGNORE-RECIPIENT"))
(in-package :cl-smtp)
(defparameter *debug* nil)
(defmacro print-debug (str)
`(when *debug*
(print ,str)))
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv3901
Modified Files:
CHANGELOG README cl-smtp.asd cl-smtp.lisp
Added Files:
smtp-output-stream.lisp
Log Message:
A lot of changes:
- add support for sending raw messages
- add character quoting in email headers (according to RFC2047)
- add condition classes for error reporting
- fixed STARTTLS
- change authentication functionality
See CHANGELOG and source.
Thanks Hans Huebner for these changes.
--- /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2007/11/11 23:10:21 1.10
+++ /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2008/04/02 18:02:28 1.11
@@ -1,3 +1,13 @@
+Version 20080202.1
+2007.02.02
+Added support for sending raw messages. (Hans Huebner)
+Fixed STARTTLS so that an EHLO command is sent after STARTTLS. (Hans Huebner)
+Changed Authentication functionality, the actual authentication method used is determined by looking at the advertised features of the SMTP server. (Hans Huebner)
+Added non-ASCII character quoting in email headers (according to RFC2047). (Hans Huebner)
+Added condition classes for error reporting. (Hans Huebner)
+Change cl-smtp.lisp, cl-smtp.asd, CHANGELOG
+Add smtp-output-stream.lisp
+
Version 20071113.1
2007.11.13
Add SSL support, thank Timothy Ritchey for the suggestions.
--- /project/cl-smtp/cvsroot/cl-smtp/README 2007/11/11 23:10:21 1.8
+++ /project/cl-smtp/cvsroot/cl-smtp/README 2008/04/02 18:02:28 1.9
@@ -25,26 +25,29 @@
Arguments:
- host (String) : hostname or ip-adress of the smtpserver
- from (String) : email adress
- - to (String or Cons of Strings) : email adress
+ - to (String or List of Strings) : email adress
- subject (String) : subject text
- message (String) : message body
keywords:
- - cc (String or Cons of Strings) : email adress carbon copy
- - bcc (String or Cons of Strings): email adress blind carbon copy
+ - cc (String or List of Strings) : email adress carbon copy
+ - bcc (String or List of Strings): email adress blind carbon copy
- reply-to (String) : email adress
- displayname (String) : displayname of the sender
- - extra-headers (Cons) : extra headers as alist
+ - extra-headers (List) : extra headers as alist
- html-message (String) : message body formatted with HTML tags
- - authentication (Cons) : list with 3 elements
- (:method "username" "password")
+ - authentication (List) : list with 2 or elements
+ ([:method] "username" "password")
method is a keyword :plain or :login
+ If the method is not specified, the
+ proper method is determined automatically.
- attachments (String or Pathname: attachments to send
- Cons of String/Pathnames)
+ List of String/Pathnames)
- buffer-size (Number default 256): controls how much of a attachment file
is read on each loop before encoding
and transmitting the contents,
- the number is interpretted in KB
- - ssl (Boolean) : if true than use the STARTTLS functionality to make a ssl connection
+ the number is interpreted in KB
+ - ssl (or t :starttls :tls) : if t or :STARTTLS: use the STARTTLS functionality
+ if :TLS: use TLS directly
Returns nil or error with message
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2007/11/11 23:10:21 1.12
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2008/04/02 18:02:29 1.13
@@ -16,25 +16,18 @@
;;; File: cl-smtp.asd
;;; Description: cl-smtp ASDF system definition file
-(defpackage :cl-smtp
- (:use :cl :asdf)
- (:export :send-email))
-
-(in-package :cl-smtp)
-
-(defparameter *debug* nil)
-
-(defmacro print-debug (str)
- `(when *debug*
- (print ,str)))
-
(asdf:defsystem :cl-smtp
- :version "20071113.1"
- :perform (load-op :after (op webpage)
- (pushnew :cl-smtp cl:*features*))
- :depends-on (:usocket #-allegro :cl-base64
- #-allegro :flexi-streams
- #-allegro :cl+ssl)
- :components ((:file "cl-smtp" :depends-on ("attachments"))
- (:file "attachments")
- (:file "mime-types")))
+ :version "20080202.1"
+ :perform (load-op :after (op webpage)
+ (pushnew :cl-smtp cl:*features*))
+ :depends-on (:usocket
+ :trivial-gray-streams
+ :flexi-streams
+ #-allegro :cl-base64
+ #-allegro :cl+ssl)
+ :serial t
+ :components ((:file "package")
+ (:file "attachments")
+ (:file "cl-smtp")
+ (:file "smtp-output-stream")
+ (:file "mime-types")))
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/11 23:10:21 1.11
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2008/04/02 18:02:29 1.12
@@ -34,21 +34,23 @@
(t
(error "the \"~A\" argument is not a string or cons" name))))
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (defvar *line-with-one-dot* #.(format nil "~C~C.~C~C" #\Return #\NewLine
+ #\Return #\NewLine))
+ (defvar *line-with-two-dots* #.(format nil "~C~C..~C~C" #\Return #\NewLine
+ #\Return #\NewLine)))
+
(defun mask-dot (str)
- "replace \r\n.\r\n with \r\n..\r\n"
- (let ((dotstr (format nil "~C~C.~C~C" #\Return #\NewLine
- #\Return #\NewLine))
- (maskdotsr (format nil "~C~C..~C~C" #\Return #\NewLine
- #\Return #\NewLine))
- (resultstr ""))
+ "Replace all occurences of \r\n.\r\n in STR with \r\n..\r\n"
+ (let ((resultstr ""))
(labels ((mask (tempstr)
- (let ((n (search dotstr tempstr)))
+ (let ((n (search *line-with-one-dot* tempstr)))
(cond
(n
(setf resultstr (concatenate 'string resultstr
(subseq tempstr 0 n)
- maskdotsr))
- (mask (subseq tempstr (+ n 5))))
+ *line-with-two-dots*))
+ (mask (subseq tempstr (+ n #.(length *line-with-one-dot*)))))
(t
(setf resultstr (concatenate 'string resultstr
tempstr)))))))
@@ -60,11 +62,76 @@
#+allegro (excl:string-to-base64-string str)
#-allegro (cl-base64:string-to-base64-string str))
+(define-condition smtp-error (error)
+ ())
+
+(define-condition smtp-protocol-error (smtp-error)
+ ((command :initarg :command :reader command)
+ (expected-response-code :initarg :expected-response-code :reader expected-response-code)
+ (response-code :initarg :response-code :reader response-code)
+ (response-message :initarg :response-message :reader response-message))
+ (:report (lambda (condition stream)
+ (print-unreadable-object (condition stream :type t)
+ (format stream "a command failed:~%command: ~S expected: ~A response: ~A"
+ (command condition)
+ (expected-response-code condition)
+ (response-message condition))))))
+
+(define-condition rcpt-failed (smtp-protocol-error)
+ ((recipient :initarg :recipient
+ :reader recipient))
+ (:report (lambda (condition stream)
+ (print-unreadable-object (condition stream :type t)
+ (format stream "while trying to send email through SMTP, the server rejected the recipient ~A: ~A"
+ (recipient condition)
+ (response-message condition))))))
+
+(defun smtp-command (stream command expected-response-code
+ &key (condition-class 'smtp-protocol-error)
+ condition-arguments)
+ (when command
+ (write-to-smtp stream command))
+ (multiple-value-bind (code msgstr lines)
+ (read-from-smtp stream)
+ (when (/= code expected-response-code)
+ (apply #'error
+ condition-class
+ (append condition-arguments
+ (list :command command
+ :expected-response-code expected-response-code
+ :response-code code
+ :response-message msgstr))))
+ lines))
+
+(defun do-with-smtp-mail (host from to thunk &key port authentication ssl local-hostname)
+ (usocket:with-client-socket (socket stream host port)
+ (let ((stream (smtp-handshake stream
+ :authentication authentication
+ :ssl ssl
+ :local-hostname local-hostname)))
+ (initiate-smtp-mail stream from to)
+ (funcall thunk (make-instance 'smtp-output-stream :encapsulated-stream stream))
+ (finish-smtp-mail stream))))
+
+(defmacro with-smtp-mail ((stream-var host from to &key ssl (port (if (eq :tls ssl) 465 25)) authentication local-hostname)
+ &body body)
+ "Encapsulate a SMTP MAIl conversation. A connection to the SMTP
+ server on HOST and PORT is established and a MAIL command is
+ initiated with FROM being the mail sender and TO being the list of
+ recipients. BODY is evaluated with STREAM-VAR being the stream
+ connected to the remote SMTP server. BODY is expected to write the
+ RFC2821 message (headers and body) to STREAM-VAR."
+ `(do-with-smtp-mail ,host ,from ,to
+ (lambda (,stream-var) ,@body)
+ :port ,port
+ :authentication ,authentication
+ :ssl ,ssl
+ :local-hostname ,local-hostname))
(defun send-email (host from to subject message
- &key (port 25) cc bcc reply-to extra-headers
+ &key ssl (port (if (eq :tls ssl) 465 25)) cc bcc reply-to extra-headers
html-message display-name authentication
- attachments (buffer-size 256) ssl)
+ attachments (buffer-size 256))
(send-smtp host from (check-arg to "to") subject (mask-dot message)
:port port :cc (check-arg cc "cc") :bcc (check-arg bcc "bcc")
:reply-to reply-to
@@ -78,186 +145,216 @@
256)
:ssl ssl))
-
-(defun send-smtp (host from to subject message
- &key (port 25) cc bcc reply-to extra-headers html-message
- display-name authentication attachments buffer-size ssl)
- (let* ((sock (usocket:socket-stream (usocket:socket-connect host port)))
- (boundary (make-random-boundary))
- (html-boundary (if (and attachments html-message)
- (make-random-boundary)
- boundary)))
- (unwind-protect
- (let ((stream (open-smtp-connection sock
- :authentication authentication
- :ssl ssl)))
- (send-smtp-headers stream :from from :to to :cc cc :bcc bcc
- :reply-to reply-to
- :display-name display-name
- :extra-headers extra-headers :subject subject)
- (when (or attachments html-message)
- (send-multipart-headers
- stream :attachment-boundary (when attachments boundary)
- :html-boundary html-boundary))
- ;;----------- Send the body Message ---------------------------
- ;;--- Send the proper headers depending on plain-text,
- ;;--- multi-part or html email
- (cond ((and attachments html-message)
- ;; if both present, start attachment section,
- ;; then define alternative section,
- ;; then write alternative header
- (progn
- (generate-message-header
- stream :boundary boundary :include-blank-line? nil)
- (generate-multipart-header stream html-boundary
- :multipart-type "alternative")
- (write-blank-line stream)
- (generate-message-header
- stream :boundary html-boundary :content-type *content-type*
- :content-disposition "inline" :include-blank-line? nil)))
- (attachments
- (generate-message-header
- stream :boundary boundary
- :content-type *content-type* :content-disposition "inline"
- :include-blank-line? nil))
- (html-message
- (generate-message-header
- stream :boundary html-boundary :content-type *content-type*
- :content-disposition "inline"))
- (t
- (generate-message-header stream :content-type *content-type*
- :include-blank-line? nil)))
- (write-blank-line stream)
- (write-to-smtp stream message)
- (write-blank-line stream)
- ;;---------- Send Html text if needed -------------------------
- (when html-message
- (generate-message-header
- stream :boundary html-boundary
- :content-type "text/html; charset=ISO-8859-1"
- :content-disposition "inline")
- (write-to-smtp stream html-message)
- (send-end-marker stream html-boundary))
- ;;---------- Send Attachments -----------------------------------
- (when attachments
- (dolist (attachment attachments)
- (send-attachment stream attachment boundary buffer-size))
- (send-end-marker stream boundary))
- (write-char #\. stream)
- (write-blank-line stream)
- (force-output stream)
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 250)
- (error "Message send failed: ~A" msgstr)))
- (write-to-smtp stream "QUIT")
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 221)
- (error "in QUIT command:: ~A" msgstr))))
- (close sock))))
-
-(defun open-smtp-connection (stream &key authentication ssl)
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 220)
- (error "wrong response from smtp server: ~A" msgstr)))
- (when ssl
- (write-to-smtp stream (format nil "EHLO ~A"
- (usocket::get-host-name)))
- (multiple-value-bind (code msgstr lines)
- (read-from-smtp stream)
- (when (/= code 250)
- (error "wrong response from smtp server: ~A" msgstr))
- (when ssl
- (cond
- ((find "STARTTLS" lines :test #'equal)
- (print-debug "this server supports TLS")
- (write-to-smtp stream "STARTTLS")
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 220)
- (error "Unable to start TLS: ~A" msgstr))
- (setf stream
- #+allegro (socket:make-ssl-client-stream stream)
- #-allegro
- (let ((s stream))
- (cl+ssl:make-ssl-client-stream
- (cl+ssl:stream-fd stream)
- :close-callback (lambda () (close s)))))
- #-allegro
- (setf stream (flexi-streams:make-flexi-stream
- stream
- :external-format
- (flexi-streams:make-external-format
- :latin-1 :eol-style :lf)))))
- (t
- (error "this server does not supports TLS"))))))
- (cond
- (authentication
- (write-to-smtp stream (format nil "EHLO ~A"
- (usocket::get-host-name)))
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 250)
- (error "wrong response from smtp server: ~A" msgstr)))
- (cond
- ((eq (car authentication) :plain)
- (write-to-smtp stream (format nil "AUTH PLAIN ~A"
- (string-to-base64-string
- (format nil "~A~C~A~C~A"
- (cadr authentication)
- #\null (cadr authentication)
- #\null
- (caddr authentication)))))
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 235)
- (error "plain authentication failed: ~A" msgstr))))
- ((eq (car authentication) :login)
- (write-to-smtp stream "AUTH LOGIN")
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 334)
- (error "login authentication failed: ~A" msgstr)))
- (write-to-smtp stream (string-to-base64-string (cadr authentication)))
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 334)
- (error "login authentication send username failed: ~A" msgstr)))
- (write-to-smtp stream (string-to-base64-string (caddr authentication)))
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 235)
- (error "login authentication send password failed: ~A" msgstr))))
- (t
- (error "authentication ~A is not supported in cl-smtp"
- (car authentication)))))
- (t
- (write-to-smtp stream (format nil "HELO ~A" (usocket::get-host-name)))
- (multiple-value-bind (code msgstr)
- (read-from-smtp stream)
- (when (/= code 250)
- (error "wrong response from smtp server: ~A" msgstr)))))
+(defun send-smtp (host from to subject message
+ &key ssl (port (if (eq :tls ssl) 465 25)) cc bcc
+ reply-to extra-headers html-message display-name
+ authentication attachments buffer-size
+ (local-hostname (usocket::get-host-name)))
+ (with-smtp-mail (stream host from (append to cc bcc)
+ :port port
+ :authentication authentication
+ :ssl ssl
+ :local-hostname local-hostname)
+ (let* ((boundary (make-random-boundary))
+ (html-boundary (if (and attachments html-message)
+ (make-random-boundary)
+ boundary)))
+ (send-mail-headers stream
+ :from from
+ :to to
+ :cc cc
+ :reply-to reply-to
+ :display-name display-name
+ :extra-headers extra-headers :subject subject)
+ (when (or attachments html-message)
+ (send-multipart-headers stream
+ :attachment-boundary (when attachments boundary)
+ :html-boundary html-boundary))
+ ;;----------- Send the body Message ---------------------------
+ ;;--- Send the proper headers depending on plain-text,
+ ;;--- multi-part or html email
+ (cond ((and attachments html-message)
+ ;; if both present, start attachment section,
+ ;; then define alternative section,
+ ;; then write alternative header
+ (progn
+ (generate-message-header
+ stream :boundary boundary :include-blank-line? nil)
+ (generate-multipart-header stream html-boundary
+ :multipart-type "alternative")
+ (write-blank-line stream)
+ (generate-message-header
+ stream :boundary html-boundary :content-type *content-type*
+ :content-disposition "inline" :include-blank-line? nil)))
+ (attachments
+ (generate-message-header
+ stream :boundary boundary
+ :content-type *content-type* :content-disposition "inline"
+ :include-blank-line? nil))
+ (html-message
+ (generate-message-header
+ stream :boundary html-boundary :content-type *content-type*
+ :content-disposition "inline"))
+ (t
+ (generate-message-header stream :content-type *content-type*
+ :include-blank-line? nil)))
+ (write-blank-line stream)
+ (write-to-smtp stream message)
+ (write-blank-line stream)
+ ;;---------- Send Html text if needed -------------------------
+ (when html-message
+ (generate-message-header
+ stream :boundary html-boundary
+ :content-type "text/html; charset=ISO-8859-1"
+ :content-disposition "inline")
+ (write-to-smtp stream html-message)
+ (send-end-marker stream html-boundary))
+ ;;---------- Send Attachments -----------------------------------
+ (when attachments
+ (dolist (attachment attachments)
+ (send-attachment stream attachment boundary buffer-size))
+ (send-end-marker stream boundary)))))
+
+(define-condition no-supported-authentication-method (smtp-error)
+ ((features :initarg :features :reader features))
+ (:report (lambda (condition stream)
+ (print-unreadable-object (condition stream :type t)
+ (format stream "SMTP authentication has been requested, but the SMTP server did not advertise any ~
+ supported authentication scheme. Features announced: ~{~S~^, ~}"
+ (features condition))))))
+
+(defun smtp-authenticate (stream authentication features)
+ "Authenticate to the SMTP server connected on STREAM.
+ AUTHENTICATION is a list of two or three elements. If the first
+ element is a keyword, it specifies the desired authentication
+ method (:PLAIN or :LOGIN), which is currently ignored. The actual
+ method used is determined by looking at the advertised features of
+ the SMTP server. The (other) two elements of the AUTHENTICATION
+ list are the login username and password. FEATURES is the list of
+ features announced by the SMTP server.
+
+ If the server does not announce any compatible authentication scheme,
+ the NO-SUPPORTED-AUTHENTICATION-METHOD error is signalled."
+ (when (keywordp (car authentication))
+ (pop authentication))
+ (let ((server-authentication (loop for i in features
+ for e = (search "AUTH " i :test #'equal)
+ when (and e (= e 0))
+ return i)))
+ (destructuring-bind (username password) authentication
+ (cond
+ ((search " PLAIN" server-authentication :test #'equal)
+ (smtp-command stream (format nil "AUTH PLAIN ~A"
+ (string-to-base64-string
+ (format nil "~A~C~A~C~A"
+ username
+ #\null username
+ #\null password)))
+ 235))
+ ((search " LOGIN" server-authentication :test #'equal)
+ (smtp-command stream "AUTH LOGIN"
+ 334)
+ (smtp-command stream (string-to-base64-string username)
+ 334)
+ (smtp-command stream (string-to-base64-string password)
+ 235))
+ (t
+ (error 'no-supported-authentication-method :features features))))))
+
+(defun smtp-handshake (stream &key authentication ssl local-hostname)
+ "Perform the initial SMTP handshake on STREAM. Returns the stream
+ to use further down in the conversation, which may be different from
+ the original stream if we switched to SSL."
+
[150 lines skipped]
--- /project/cl-smtp/cvsroot/cl-smtp/smtp-output-stream.lisp 2008/04/02 18:02:29 NONE
+++ /project/cl-smtp/cvsroot/cl-smtp/smtp-output-stream.lisp 2008/04/02 18:02:29 1.1
[237 lines skipped]
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv19188
Modified Files:
CHANGELOG README cl-smtp.asd cl-smtp.lisp
Log Message:
Add SSL support, thank Timothy Ritchey for the suggestions.
New boolean keyword argument ssl added to send-email.
--- /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2007/11/03 23:53:29 1.9
+++ /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2007/11/11 23:10:21 1.10
@@ -1,3 +1,9 @@
+Version 20071113.1
+2007.11.13
+Add SSL support, thank Timothy Ritchey for the suggestions.
+New boolean keyword argument ssl added to send-email.
+Change cl-smtp.lisp, cl-smtp.asd, README, CHANGELOG
+
Version 20071104.1
2007.11.04
Fixed bug with the file attachments to solve corrupted files when
@@ -5,7 +11,7 @@
Added automatically including mime types for attachesments
of common known extensions. (Brian Sorg)
Added Html-messages option to send-mail function. (Brian Sorg)
-Change attachments.lisp, cl-smtp.asd, cl-smtp.lisp, README, CHANGLOG
+Change attachments.lisp, cl-smtp.asd, cl-smtp.lisp, README, CHANGELOG
Add mime-type.lisp
Version 20071018.1
--- /project/cl-smtp/cvsroot/cl-smtp/README 2007/11/03 23:53:29 1.7
+++ /project/cl-smtp/cvsroot/cl-smtp/README 2007/11/11 23:10:21 1.8
@@ -6,6 +6,8 @@
with authentication support for PLAIN and LOGIN authentication method
+and ssl support with cl+ssl package
+
used cl-base64 and usocket packages (cl-base64 isn't a requirement on ACL)
See INSTALL for prerequisites and build details.
@@ -18,7 +20,7 @@
(cl-smtp:send-email host from to subject message
&key (port 25) cc bcc reply-to extra-headers html-message
- authentication attachments (buffer-size 256))
+ authentication attachments (buffer-size 256) ssl)
Arguments:
- host (String) : hostname or ip-adress of the smtpserver
@@ -41,7 +43,8 @@
- buffer-size (Number default 256): controls how much of a attachment file
is read on each loop before encoding
and transmitting the contents,
- the number is interpretted in KB
+ the number is interpretted in KB
+ - ssl (Boolean) : if true than use the STARTTLS functionality to make a ssl connection
Returns nil or error with message
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2007/11/05 19:58:24 1.11
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2007/11/11 23:10:21 1.12
@@ -29,10 +29,12 @@
(print ,str)))
(asdf:defsystem :cl-smtp
- :version "20071105.1"
+ :version "20071113.1"
:perform (load-op :after (op webpage)
(pushnew :cl-smtp cl:*features*))
- :depends-on (:usocket #-allegro :cl-base64)
+ :depends-on (:usocket #-allegro :cl-base64
+ #-allegro :flexi-streams
+ #-allegro :cl+ssl)
:components ((:file "cl-smtp" :depends-on ("attachments"))
(:file "attachments")
(:file "mime-types")))
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/05 19:58:24 1.10
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/11 23:10:21 1.11
@@ -63,8 +63,8 @@
(defun send-email (host from to subject message
&key (port 25) cc bcc reply-to extra-headers
- html-message display-name authentication
- attachments (buffer-size 256))
+ html-message display-name authentication
+ attachments (buffer-size 256) ssl)
(send-smtp host from (check-arg to "to") subject (mask-dot message)
:port port :cc (check-arg cc "cc") :bcc (check-arg bcc "bcc")
:reply-to reply-to
@@ -75,206 +75,244 @@
:attachments (check-arg attachments "attachments")
:buffer-size (if (numberp buffer-size)
buffer-size
- 256)))
+ 256)
+ :ssl ssl))
(defun send-smtp (host from to subject message
&key (port 25) cc bcc reply-to extra-headers html-message
- display-name authentication attachments buffer-size)
+ display-name authentication attachments buffer-size ssl)
(let* ((sock (usocket:socket-stream (usocket:socket-connect host port)))
(boundary (make-random-boundary))
(html-boundary (if (and attachments html-message)
(make-random-boundary)
boundary)))
(unwind-protect
- (progn
- (open-smtp-connection sock :authentication authentication)
- (send-smtp-headers sock :from from :to to :cc cc :bcc bcc
- :reply-to reply-to
- :display-name display-name
- :extra-headers extra-headers :subject subject)
- (when (or attachments html-message)
- (send-multipart-headers
- sock :attachment-boundary (when attachments boundary)
- :html-boundary html-boundary))
- ;;----------- Send the body Message ---------------------------
- ;;--- Send the proper headers depending on plain-text,
- ;;--- multi-part or html email
- (cond ((and attachments html-message)
- ;; if both present, start attachment section,
- ;; then define alternative section,
- ;; then write alternative header
- (progn
- (generate-message-header
- sock :boundary boundary :include-blank-line? nil)
- (generate-multipart-header sock html-boundary
- :multipart-type "alternative")
- (write-blank-line sock)
- (generate-message-header
- sock :boundary html-boundary :content-type *content-type*
- :content-disposition "inline" :include-blank-line? nil)))
- (attachments
- (generate-message-header
- sock :boundary boundary
- :content-type *content-type* :content-disposition "inline"
- :include-blank-line? nil))
- (html-message
- (generate-message-header
- sock :boundary html-boundary :content-type *content-type*
- :content-disposition "inline"))
- (t
- (generate-message-header sock :content-type *content-type*
- :include-blank-line? nil)))
- (write-blank-line sock)
- (write-to-smtp sock message)
- (write-blank-line sock)
- ;;---------- Send Html text if needed -------------------------
- (when html-message
- (generate-message-header
- sock :boundary html-boundary
- :content-type "text/html; charset=ISO-8859-1"
- :content-disposition "inline")
- (write-to-smtp sock html-message)
- (send-end-marker sock html-boundary))
- ;;---------- Send Attachments -----------------------------------
- (when attachments
- (dolist (attachment attachments)
- (send-attachment sock attachment boundary buffer-size))
- (send-end-marker sock boundary))
- (write-char #\. sock)
- (write-blank-line sock)
- (force-output sock)
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 250)
- (error "Message send failed: ~A" msgstr)))
- (write-to-smtp sock "QUIT")
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 221)
- (error "in QUIT command:: ~A" msgstr))))
+ (let ((stream (open-smtp-connection sock
+ :authentication authentication
+ :ssl ssl)))
+ (send-smtp-headers stream :from from :to to :cc cc :bcc bcc
+ :reply-to reply-to
+ :display-name display-name
+ :extra-headers extra-headers :subject subject)
+ (when (or attachments html-message)
+ (send-multipart-headers
+ stream :attachment-boundary (when attachments boundary)
+ :html-boundary html-boundary))
+ ;;----------- Send the body Message ---------------------------
+ ;;--- Send the proper headers depending on plain-text,
+ ;;--- multi-part or html email
+ (cond ((and attachments html-message)
+ ;; if both present, start attachment section,
+ ;; then define alternative section,
+ ;; then write alternative header
+ (progn
+ (generate-message-header
+ stream :boundary boundary :include-blank-line? nil)
+ (generate-multipart-header stream html-boundary
+ :multipart-type "alternative")
+ (write-blank-line stream)
+ (generate-message-header
+ stream :boundary html-boundary :content-type *content-type*
+ :content-disposition "inline" :include-blank-line? nil)))
+ (attachments
+ (generate-message-header
+ stream :boundary boundary
+ :content-type *content-type* :content-disposition "inline"
+ :include-blank-line? nil))
+ (html-message
+ (generate-message-header
+ stream :boundary html-boundary :content-type *content-type*
+ :content-disposition "inline"))
+ (t
+ (generate-message-header stream :content-type *content-type*
+ :include-blank-line? nil)))
+ (write-blank-line stream)
+ (write-to-smtp stream message)
+ (write-blank-line stream)
+ ;;---------- Send Html text if needed -------------------------
+ (when html-message
+ (generate-message-header
+ stream :boundary html-boundary
+ :content-type "text/html; charset=ISO-8859-1"
+ :content-disposition "inline")
+ (write-to-smtp stream html-message)
+ (send-end-marker stream html-boundary))
+ ;;---------- Send Attachments -----------------------------------
+ (when attachments
+ (dolist (attachment attachments)
+ (send-attachment stream attachment boundary buffer-size))
+ (send-end-marker stream boundary))
+ (write-char #\. stream)
+ (write-blank-line stream)
+ (force-output stream)
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
+ (when (/= code 250)
+ (error "Message send failed: ~A" msgstr)))
+ (write-to-smtp stream "QUIT")
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
+ (when (/= code 221)
+ (error "in QUIT command:: ~A" msgstr))))
(close sock))))
-(defun open-smtp-connection (sock &key authentication)
+(defun open-smtp-connection (stream &key authentication ssl)
(multiple-value-bind (code msgstr)
- (read-from-smtp sock)
+ (read-from-smtp stream)
(when (/= code 220)
(error "wrong response from smtp server: ~A" msgstr)))
+ (when ssl
+ (write-to-smtp stream (format nil "EHLO ~A"
+ (usocket::get-host-name)))
+ (multiple-value-bind (code msgstr lines)
+ (read-from-smtp stream)
+ (when (/= code 250)
+ (error "wrong response from smtp server: ~A" msgstr))
+ (when ssl
+ (cond
+ ((find "STARTTLS" lines :test #'equal)
+ (print-debug "this server supports TLS")
+ (write-to-smtp stream "STARTTLS")
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
+ (when (/= code 220)
+ (error "Unable to start TLS: ~A" msgstr))
+ (setf stream
+ #+allegro (socket:make-ssl-client-stream stream)
+ #-allegro
+ (let ((s stream))
+ (cl+ssl:make-ssl-client-stream
+ (cl+ssl:stream-fd stream)
+ :close-callback (lambda () (close s)))))
+ #-allegro
+ (setf stream (flexi-streams:make-flexi-stream
+ stream
+ :external-format
+ (flexi-streams:make-external-format
+ :latin-1 :eol-style :lf)))))
+ (t
+ (error "this server does not supports TLS"))))))
(cond
- (authentication
- (write-to-smtp sock (format nil "EHLO ~A" (usocket::get-host-name)))
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
+ (authentication
+ (write-to-smtp stream (format nil "EHLO ~A"
+ (usocket::get-host-name)))
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
(when (/= code 250)
(error "wrong response from smtp server: ~A" msgstr)))
- (cond
- ((eq (car authentication) :plain)
- (write-to-smtp sock (format nil "AUTH PLAIN ~A"
- (string-to-base64-string
- (format nil "~A~C~A~C~A" (cadr authentication)
- #\null (cadr authentication) #\null
- (caddr authentication)))))
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 235)
- (error "plain authentication failed: ~A" msgstr))))
- ((eq (car authentication) :login)
- (write-to-smtp sock "AUTH LOGIN")
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 334)
- (error "login authentication failed: ~A" msgstr)))
- (write-to-smtp sock (string-to-base64-string (cadr authentication)))
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 334)
- (error "login authentication send username failed: ~A" msgstr)))
- (write-to-smtp sock (string-to-base64-string (caddr authentication)))
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 235)
- (error "login authentication send password failed: ~A" msgstr))))
- (t
- (error "authentication ~A is not supported in cl-smtp"
- (car authentication)))))
+ (cond
+ ((eq (car authentication) :plain)
+ (write-to-smtp stream (format nil "AUTH PLAIN ~A"
+ (string-to-base64-string
+ (format nil "~A~C~A~C~A"
+ (cadr authentication)
+ #\null (cadr authentication)
+ #\null
+ (caddr authentication)))))
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
+ (when (/= code 235)
+ (error "plain authentication failed: ~A" msgstr))))
+ ((eq (car authentication) :login)
+ (write-to-smtp stream "AUTH LOGIN")
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
+ (when (/= code 334)
+ (error "login authentication failed: ~A" msgstr)))
+ (write-to-smtp stream (string-to-base64-string (cadr authentication)))
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
+ (when (/= code 334)
+ (error "login authentication send username failed: ~A" msgstr)))
+ (write-to-smtp stream (string-to-base64-string (caddr authentication)))
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp stream)
+ (when (/= code 235)
+ (error "login authentication send password failed: ~A" msgstr))))
+ (t
+ (error "authentication ~A is not supported in cl-smtp"
+ (car authentication)))))
(t
- (write-to-smtp sock (format nil "HELO ~A" (usocket::get-host-name)))
+ (write-to-smtp stream (format nil "HELO ~A" (usocket::get-host-name)))
(multiple-value-bind (code msgstr)
- (read-from-smtp sock)
+ (read-from-smtp stream)
(when (/= code 250)
- (error "wrong response from smtp server: ~A" msgstr))))))
+ (error "wrong response from smtp server: ~A" msgstr)))))
+ stream)
-(defun send-smtp-headers (sock
+(defun send-smtp-headers (stream
&key from to cc bcc reply-to
extra-headers display-name subject)
- (write-to-smtp sock
+ (write-to-smtp stream
(format nil "MAIL FROM:~@[~A ~]<~A>" display-name from))
(multiple-value-bind (code msgstr)
- (read-from-smtp sock)
+ (read-from-smtp stream)
(when (/= code 250)
(error "in MAIL FROM command: ~A" msgstr)))
- (compute-rcpt-command sock to)
- (compute-rcpt-command sock cc)
- (compute-rcpt-command sock bcc)
- (write-to-smtp sock "DATA")
+ (compute-rcpt-command stream to)
+ (compute-rcpt-command stream cc)
+ (compute-rcpt-command stream bcc)
+ (write-to-smtp stream "DATA")
(multiple-value-bind (code msgstr)
- (read-from-smtp sock)
+ (read-from-smtp stream)
(when (/= code 354)
(error "in DATA command: ~A" msgstr)))
- (write-to-smtp sock (format nil "Date: ~A" (get-email-date-string)))
- (write-to-smtp sock (format nil "From: ~@[~A <~]~A~@[>~]"
- display-name from display-name))
- (write-to-smtp sock (format nil "To: ~{ ~a~^,~}" to))
+ (write-to-smtp stream (format nil "Date: ~A" (get-email-date-string)))
+ (write-to-smtp stream (format nil "From: ~@[~A <~]~A~@[>~]"
+ display-name from display-name))
+ (write-to-smtp stream (format nil "To: ~{ ~a~^,~}" to))
(when cc
- (write-to-smtp sock (format nil "Cc: ~{ ~a~^,~}" cc)))
- (write-to-smtp sock (format nil "Subject: ~A" subject))
- (write-to-smtp sock (format nil "X-Mailer: cl-smtp ~A"
- *x-mailer*))
+ (write-to-smtp stream (format nil "Cc: ~{ ~a~^,~}" cc)))
+ (write-to-smtp stream (format nil "Subject: ~A" subject))
+ (write-to-smtp stream (format nil "X-Mailer: cl-smtp ~A"
+ *x-mailer*))
(when reply-to
- (write-to-smtp sock (format nil "Reply-To: ~A" reply-to)))
+ (write-to-smtp stream (format nil "Reply-To: ~A" reply-to)))
(when (and extra-headers
(listp extra-headers))
(dolist (l extra-headers)
- (write-to-smtp sock
+ (write-to-smtp stream
(format nil "~A: ~{~a~^,~}" (car l) (rest l)))))
- (write-to-smtp sock "Mime-Version: 1.0"))
+ (write-to-smtp stream "Mime-Version: 1.0"))
-(defun send-multipart-headers (sock &key attachment-boundary html-boundary)
+(defun send-multipart-headers (stream &key attachment-boundary html-boundary)
(cond (attachment-boundary
- (generate-multipart-header sock attachment-boundary
+ (generate-multipart-header stream attachment-boundary
:multipart-type "mixed"))
(html-boundary (generate-multipart-header
- sock html-boundary
+ stream html-boundary
:multipart-type "alternative"))
(t nil)))
-(defun compute-rcpt-command (sock adresses)
+(defun compute-rcpt-command (stream adresses)
(dolist (to adresses)
- (write-to-smtp sock (format nil "RCPT TO:<~A>" to))
+ (write-to-smtp stream (format nil "RCPT TO:<~A>" to))
(multiple-value-bind (code msgstr)
- (read-from-smtp sock)
+ (read-from-smtp stream)
(when (/= code 250)
(error "in RCPT TO command: ~A" msgstr)))))
-(defun write-to-smtp (sock command)
+(defun write-to-smtp (stream command)
(print-debug (format nil "to server: ~A" command))
- (write-string command sock)
- (write-char #\Return sock)
- (write-char #\NewLine sock)
- (force-output sock))
-
-(defun write-blank-line (sock)
- (write-char #\Return sock)
- (write-char #\NewLine sock)
- (force-output sock))
-
-(defun read-from-smtp (sock)
- (let* ((line (read-line sock))
+ (write-string command stream)
+ (write-char #\Return stream)
+ (write-char #\NewLine stream)
+ (force-output stream))
+
+(defun write-blank-line (stream)
+ (write-char #\Return stream)
+ (write-char #\NewLine stream)
+ (force-output stream))
+
+(defun read-from-smtp (stream &optional lines)
+ (let* ((line (read-line stream))
+ (response (string-trim '(#\Return #\NewLine) (subseq line 4)))
(response-code (parse-integer line :start 0 :junk-allowed t)))
(print-debug (format nil "from server: ~A" line))
(if (= (char-code (elt line 3)) (char-code #\-))
- (read-from-smtp sock)
- (values response-code line))))
[5 lines skipped]
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv8540
Modified Files:
attachments.lisp cl-smtp.asd cl-smtp.lisp
Added Files:
index.html style.css
Log Message:
- for allegro cl don't use cl-base64
- use write-blank-line in send-smtp
--- /project/cl-smtp/cvsroot/cl-smtp/attachments.lisp 2007/11/03 23:53:29 1.5
+++ /project/cl-smtp/cvsroot/cl-smtp/attachments.lisp 2007/11/05 19:58:24 1.6
@@ -133,9 +133,9 @@
#-allegro
(cl-base64:usb8-array-to-base64-stream
buffer sock :columns wrap-at-column)
- ;; otherwise process file in chunks.
+ ;; otherwise process file in chunks.
;; The extra encoded-string,
- ;; and its subseq functions are brute force methods
+ ;; and its subseq functions are brute force methods
;; to properly handle the wrap-at-column feature
;; between buffers.
;; Not the most efficient way,
@@ -148,7 +148,7 @@
buffer))
(encoded-string
#+allegro
- (cl-base64:usb8-array-to-base64-string
+ (excl:usb8-array-to-base64-string
trimmed-buffer)
#-allegro
(cl-base64:usb8-array-to-base64-string
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2007/11/03 23:53:29 1.10
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2007/11/05 19:58:24 1.11
@@ -29,10 +29,10 @@
(print ,str)))
(asdf:defsystem :cl-smtp
- :version "20071104.1"
+ :version "20071105.1"
:perform (load-op :after (op webpage)
(pushnew :cl-smtp cl:*features*))
:depends-on (:usocket #-allegro :cl-base64)
:components ((:file "cl-smtp" :depends-on ("attachments"))
- (:file "attachments")
- (:file "mime-types")))
+ (:file "attachments")
+ (:file "mime-types")))
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/04 00:01:49 1.9
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/05 19:58:24 1.10
@@ -89,7 +89,10 @@
(unwind-protect
(progn
(open-smtp-connection sock :authentication authentication)
- (send-smtp-headers sock :from from :to to :cc cc :bcc bcc :reply-to reply-to :display-name display-name :extra-headers extra-headers :subject subject)
+ (send-smtp-headers sock :from from :to to :cc cc :bcc bcc
+ :reply-to reply-to
+ :display-name display-name
+ :extra-headers extra-headers :subject subject)
(when (or attachments html-message)
(send-multipart-headers
sock :attachment-boundary (when attachments boundary)
@@ -139,8 +142,7 @@
(send-attachment sock attachment boundary buffer-size))
(send-end-marker sock boundary))
(write-char #\. sock)
- (write-char #\Return sock)
- (write-char #\NewLine sock)
+ (write-blank-line sock)
(force-output sock)
(multiple-value-bind (code msgstr)
(read-from-smtp sock)
--- /project/cl-smtp/cvsroot/cl-smtp/index.html 2007/11/05 19:58:24 NONE
+++ /project/cl-smtp/cvsroot/cl-smtp/index.html 2007/11/05 19:58:24 1.1
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>CL-SMTP</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
</head>
<body>
<div class="header">
<h1>CL-SMTP at common-lisp.net</h1>
</div>
<h3>Introduction</h3>
<p>CL-SMTP is a simple lisp Networking Library that provides SMTP client protocol, supported LOGIN and PLAIN authentication methods.</p>
<p><b>New Version</b> [20071018.1] Reverted the non allegro base64 functionality in attachment.lisp, now it is used cl-base64 again. Thanks Attila Lendvai for the bug report.</p>
<h3>Download</h3>
<p>ASDF package <a href="cl-smtp.tar.gz">cl-smtp.tar.gz</a></p>
<h3>CVS</h3>
<p>You can <a
href="http://common-lisp.net/cgi-bin/viewcvs.cgi/?cvsroot=cl-smtp">
browse our CVS repository</a> or download the current development tree via
anonymous cvs, as described <a href="/faq.shtml#checkout">here</a></p>
<h3>Portability</h3>
<p>CL-SMTP requires USOCKET and CL-BASE64 (CL-BASE64 isn't a requirement on ACL)</p>
<p>It works in all implementations supported by its dependencies (Allegro, SBCL, CMU CL, OpenMCL, Lispworks, CLISP and ECL).</p>
<p>Test results for Linux/x86/amd64:</p>
<table cellspacing="0" cellpadding="2" border="1">
<thead>
<tr>
<th>Lisp Implementation</th>
<th>Status</th>
<th>Comments</th>
</tr>
</thead>
<tr>
<td>Allegro</td>
<td class="working">working</td>
</tr>
<tr>
<td>CLISP</td>
<td class="working">working</td>
</tr>
<tr>
<td>CMU CL</td>
<td class="working">working</td>
</tr>
<tr>
<td>Lispworks</td>
<td class="working">working</td>
</tr>
<tr>
<td>SBCL</td>
<td class="working">working</td>
</tr>
<tr>
<td>OpemMCL</td>
<td class="working">working</td>
</tr>
</table>
<h3>Mailing Lists</h3>
<ul>
<li>
<a
href="http://www.common-lisp.net/mailman/listinfo/cl-smtp-devel">
CL-SMTP-devel</a><br/>for developers</li>
<li>
<a
href="http://www.common-lisp.net/mailman/listinfo/cl-smtp-cvs">
CL-SMTP-cvs</a><br/>CVS log feed.</li>
</ul>
<div class="footer">
<a href="mailto:jidzikowski (at) common-lisp (dot) net">Jan Idzikowski</a>, 24. May 2005.
</div>
<div class="check">
<a href="http://validator.w3.org/check/referer">
Valid XHTML 1.0 Strict</a>
</div>
</body>
</html>
--- /project/cl-smtp/cvsroot/cl-smtp/style.css 2007/11/05 19:58:24 NONE
+++ /project/cl-smtp/cvsroot/cl-smtp/style.css 2007/11/05 19:58:24 1.1
.header {
font-size: medium;
background-color:#336699;
color:#ffffff;
border-style:solid;
border-width: 5px;
border-color:#002244;
padding: 1mm 1mm 1mm 5mm;
}
.footer {
font-size: small;
font-style: italic;
text-align: right;
background-color:#336699;
color:#ffffff;
border-style:solid;
border-width: 2px;
border-color:#002244;
padding: 1mm 1mm 1mm 1mm;
}
.footer a:link {
font-weight:bold;
color:#ffffff;
text-decoration:underline;
}
.footer a:visited {
font-weight:bold;
color:#ffffff;
text-decoration:underline;
}
.footer a:hover {
font-weight:bold;
color:#002244;
text-decoration:underline; }
.check {font-size: x-small;
text-align:right;}
.check a:link { font-weight:bold;
color:#a0a0ff;
text-decoration:underline; }
.check a:visited { font-weight:bold;
color:#a0a0ff;
text-decoration:underline; }
.check a:hover { font-weight:bold;
color:#000000;
text-decoration:underline; }
th { background-color: #8b0000;
color: white;
text-align: left; }
.working { background-color: #90ee90; }
.broken { background-color: #c5c5c5; }
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv13911
Modified Files:
cl-smtp.lisp
Log Message:
don't set multipart header when send pure text message
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/03 23:53:29 1.8
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/04 00:01:49 1.9
@@ -90,9 +90,10 @@
(progn
(open-smtp-connection sock :authentication authentication)
(send-smtp-headers sock :from from :to to :cc cc :bcc bcc :reply-to reply-to :display-name display-name :extra-headers extra-headers :subject subject)
- (send-multipart-headers
- sock :attachment-boundary (when attachments boundary)
- :html-boundary html-boundary)
+ (when (or attachments html-message)
+ (send-multipart-headers
+ sock :attachment-boundary (when attachments boundary)
+ :html-boundary html-boundary))
;;----------- Send the body Message ---------------------------
;;--- Send the proper headers depending on plain-text,
;;--- multi-part or html email
1
0
Update of /project/cl-smtp/cvsroot/cl-smtp
In directory clnet:/tmp/cvs-serv13213
Modified Files:
CHANGELOG README attachments.lisp cl-smtp.asd cl-smtp.lisp
Added Files:
mime-types.lisp
Log Message:
Fixed bug with the file attachments to solve corrupted files when
processed with chunking turned on. (Brian Sorg)
Added automatically including mime types for attachesments
of common known extensions. (Brian Sorg)
Added Html-messages option to send-mail function. (Brian Sorg)
--- /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2007/10/18 19:10:37 1.8
+++ /project/cl-smtp/cvsroot/cl-smtp/CHANGELOG 2007/11/03 23:53:29 1.9
@@ -1,3 +1,13 @@
+Version 20071104.1
+2007.11.04
+Fixed bug with the file attachments to solve corrupted files when
+processed with chunking turned on. (Brian Sorg)
+Added automatically including mime types for attachesments
+of common known extensions. (Brian Sorg)
+Added Html-messages option to send-mail function. (Brian Sorg)
+Change attachments.lisp, cl-smtp.asd, cl-smtp.lisp, README, CHANGLOG
+Add mime-type.lisp
+
Version 20071018.1
2007.10.18
Reverted the non allegro base64 functionality in attachment.lisp,
--- /project/cl-smtp/cvsroot/cl-smtp/README 2007/09/04 18:54:06 1.6
+++ /project/cl-smtp/cvsroot/cl-smtp/README 2007/11/03 23:53:29 1.7
@@ -17,8 +17,8 @@
------------------------------------------------
(cl-smtp:send-email host from to subject message
- &key (port 25) cc bcc reply-to extra-headers authentication
- attachments (buffer-size 256))
+ &key (port 25) cc bcc reply-to extra-headers html-message
+ authentication attachments (buffer-size 256))
Arguments:
- host (String) : hostname or ip-adress of the smtpserver
@@ -32,6 +32,7 @@
- reply-to (String) : email adress
- displayname (String) : displayname of the sender
- extra-headers (Cons) : extra headers as alist
+ - html-message (String) : message body formatted with HTML tags
- authentication (Cons) : list with 3 elements
(:method "username" "password")
method is a keyword :plain or :login
--- /project/cl-smtp/cvsroot/cl-smtp/attachments.lisp 2007/10/16 17:33:19 1.4
+++ /project/cl-smtp/cvsroot/cl-smtp/attachments.lisp 2007/11/03 23:53:29 1.5
@@ -37,98 +37,131 @@
(dotimes (i (length chars) arr)
(setf (aref arr i) (pop chars)))))
-(defun make-random-boundary (&optional (length 50) (boundary-chars *boundary-chars*))
+(defun make-random-boundary (&optional (length 30)
+ (boundary-chars *boundary-chars*))
(let ((boundary (make-string length))
+ (prefix "_---------_")
(chars-length (length boundary-chars)))
- (dotimes (i length boundary)
- (setf (aref boundary i) (svref *boundary-chars* (random chars-length))))))
+ (dotimes (i length (concatenate 'string prefix boundary))
+ (setf (aref boundary i)
+ (svref *boundary-chars* (random chars-length))))))
-(defun generate-multipart-header (sock boundary)
+(defun generate-multipart-header (sock boundary &key (multipart-type "mixed"))
(write-to-smtp sock
- (format nil "Content-type: multipart/mixed;~%~tBoundary=\"~a\""
- boundary)))
+ (format nil "Content-type: multipart/~a;~%~tBoundary=\"~a\""
+ multipart-type boundary)))
+(defun generate-message-header (sock
+ &key boundary ;; uniques string of character -- see make-random-boundary
+ content-type ;; "text/plain; charset=ISO-8859-1"
+ content-disposition ;; inline attachment
+ content-transfer-encoding ;; 7 bit or 8 bit
+ (include-blank-line? t))
+ (when boundary
+ (write-to-smtp sock (format nil "--~a" boundary)))
+ (when content-type
+ (write-to-smtp sock (format nil "Content-type: ~a" content-type)))
+ (when content-disposition
+ (write-to-smtp sock (format nil "Content-Disposition: ~A"
+ content-disposition)))
+ (when content-transfer-encoding
+ (write-to-smtp sock (format nil "Content-Transfer-Encoding: ~A"
+ content-transfer-encoding)))
+ (when include-blank-line? (write-blank-line sock)))
-(defun wrap-message-with-multipart-dividers (message boundary)
+(defun send-attachment-header (sock boundary name)
- (concatenate 'string (format nil "--~a~%" boundary)
- (format nil "Content-type: text/plain~%")
- (format nil "Content-Disposition: inline~%")
- (format nil "~%")
- message (format nil "~%")))
+ (generate-message-header
+ sock
+ :boundary boundary
+ :content-type (format nil "~a;~%~tname=\"~a\"" (lookup-mime-type name) name)
+ :content-transfer-encoding "base64"
+ :content-disposition (format nil "attachment; filename=\"~a\"" name)))
+
+(defun send-end-marker (sock boundary)
+ ;; Note the -- at beginning and end of boundary is required
+ (write-to-smtp sock (format nil "~%--~a--~%" boundary)))
(defun send-attachment (sock attachment boundary buffer-size)
- (print-debug (format nil "Sending attachment: ~a" attachment))
(when (probe-file attachment)
(let ((name (file-namestring attachment)))
(send-attachment-header sock boundary name)
- (base64-encode-file attachment sock :buffer-size buffer-size)
- )))
-
-(defun send-attachment-header (sock boundary name)
+ (base64-encode-file attachment sock :buffer-size buffer-size))))
- (write-to-smtp sock
- (format nil "~%--~a~%Content-type: application/octet-stream;~%~tname=\"~a\"~%Content-Transfer-Encoding: base64~%Content-Disposition: attachment; filename=\"~a\"~%"
- boundary
- name
- name)))
-
-(defun send-attachments-end-marker (sock boundary)
- (write-to-smtp sock
- (format nil "~%--~a--~%" boundary)))
-
(defun base64-encode-file (file-in sock
&key
(buffer-size 256) ;; in KB
- (wrap-at-column 76))
- (declare (ignorable wrap-at-column))
- (let* ((max-buffer-size (* buffer-size 1024))
- (byte-count 0)
- (buffer (make-array max-buffer-size
- :element-type '(unsigned-byte 8))))
+ (wrap-at-column 70))
+ "Encodes the file contents given by file-in, which can be of any form appropriate to with-open-file, and write the base-64 encoded version to sock, which is a socket.
+
+Buffer-size, given in KB, controls how much of the file is processed and written to the socket at one time. A buffer-size of 0, processes the file all at once, regardless of its size. One will have to weigh the speed vs, memory consuption risks when chosing which way is best.
+
+Wrap-at-column controls where the encode string is divided for line breaks."
(when (probe-file file-in)
;;-- open filein ---------
(with-open-file (strm-in file-in
:element-type '(unsigned-byte 8))
-
- (loop
- (setq byte-count 0)
- ;; read a portion of the file into the buffer
- (setq byte-count (dotimes (i max-buffer-size max-buffer-size)
- (let ((bchar (read-byte strm-in nil 'EOF)))
- (if (eql bchar 'EOF)
- (return i)
- (setf (aref buffer i) bchar)))))
- (print-debug (format nil "~%** Byte Count ~a~%" byte-count))
- ;; encode the buffer and write out to stream
- #+allegro
- (write-string (excl:usb8-array-to-base64-string
- (if (< byte-count max-buffer-size)
- (trimmed-buffer byte-count buffer)
- buffer)
- wrap-at-column) sock)
- #-allegro
- (cl-base64:usb8-array-to-base64-stream
- (if (< byte-count max-buffer-size)
- (trimmed-buffer byte-count buffer)
- buffer)
- sock :columns wrap-at-column)
- (force-output sock)
- ;;-- when finished reading exit do loop
- (when (< byte-count max-buffer-size)
- (return)))))))
-
-(defun trimmed-buffer (byte-count buffer)
- "Creates an array the length of byte-count and copies contents of buffer into it.
-Needed in Lispworks, Lispworks initialized all elements of the buffer array when it was made, allegro doesn't
-seem to have this behavior"
- (let ((trimmed-buffer (make-array byte-count :element-type '(unsigned-byte 8))))
- (dotimes (i byte-count trimmed-buffer)
- (setf (aref trimmed-buffer i) (aref buffer i)))))
-
-
-
-
-
-
-
+ (let* ((;; convert buffer size given to bytes
+ ;; or compute bytes based on file
+ max-buffer-size
+ (if (zerop buffer-size)
+ (file-length strm-in)
+ ;; Ensures 64 bit encoding is properly
+ ;; divided so that filler
+ ;; characters are not required between chunks
+ (* 24 (truncate (/ (* buffer-size 1024) 24)))))
+ (column-count 0)
+ (eof? nil)
+ (buffer (make-array max-buffer-size
+ :element-type '(unsigned-byte 8))))
+ (loop
+ (print-debug (format nil "~%Process attachment ~a~%" file-in))
+ (let* ((;; read a portion of the file into the buffer arrary and
+ ;; returns the index where it stopped
+ byte-count (dotimes (i max-buffer-size max-buffer-size)
+ (let ((bchar (read-byte strm-in nil 'EOF)))
+ (if (eql bchar 'EOF)
+ (progn
+ (setq eof? t)
+ (return i))
+ (setf (aref buffer i) bchar))))))
+ (if (zerop buffer-size)
+ ;; send file all at once to socket.
+ #+allegro
+ (write-string (excl:usb8-array-to-base64-string
+ buffer wrap-at-column) sock)
+ #-allegro
+ (cl-base64:usb8-array-to-base64-stream
+ buffer sock :columns wrap-at-column)
+ ;; otherwise process file in chunks.
+ ;; The extra encoded-string,
+ ;; and its subseq functions are brute force methods
+ ;; to properly handle the wrap-at-column feature
+ ;; between buffers.
+ ;; Not the most efficient way,
+ ;; but it works and uses existing functions
+ ;; in the cl-base64 package.
+ (let* ((;; drops off extra elements that were not filled in in reading, this is important for lisp systems that default a value into
+ ;; the array when it is created. -- ie Lispworks, SBCL
+ trimmed-buffer (if eof?
+ (subseq buffer 0 byte-count)
+ buffer))
+ (encoded-string
+ #+allegro
+ (cl-base64:usb8-array-to-base64-string
+ trimmed-buffer)
+ #-allegro
+ (cl-base64:usb8-array-to-base64-string
+ trimmed-buffer)))
+ (loop for ch across encoded-string
+ do (progn
+ (write-char ch sock)
+ (incf column-count)
+ (when (= column-count wrap-at-column)
+ (setq column-count 0)
+ (write-char #\Newline sock))))))
+ (force-output sock)
+ (print-debug (format nil "~% Eof is ~a~%" eof?))
+ (when (or (zerop buffer-size)
+ eof?)
+ (return))))))))
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2007/10/18 19:10:37 1.9
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.asd 2007/11/03 23:53:29 1.10
@@ -29,7 +29,10 @@
(print ,str)))
(asdf:defsystem :cl-smtp
- :version "20071018.1"
+ :version "20071104.1"
+ :perform (load-op :after (op webpage)
+ (pushnew :cl-smtp cl:*features*))
:depends-on (:usocket #-allegro :cl-base64)
:components ((:file "cl-smtp" :depends-on ("attachments"))
- (:file "attachments")))
+ (:file "attachments")
+ (:file "mime-types")))
--- /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/09/04 18:56:58 1.7
+++ /project/cl-smtp/cvsroot/cl-smtp/cl-smtp.lisp 2007/11/03 23:53:29 1.8
@@ -18,6 +18,8 @@
(in-package :cl-smtp)
+(defparameter *content-type* "text/plain; charset=ISO-8859-1")
+
(defparameter *x-mailer* (format nil "(~A ~A)"
(lisp-implementation-type)
(lisp-implementation-version)))
@@ -61,12 +63,13 @@
(defun send-email (host from to subject message
&key (port 25) cc bcc reply-to extra-headers
- display-name authentication
+ html-message display-name authentication
attachments (buffer-size 256))
(send-smtp host from (check-arg to "to") subject (mask-dot message)
:port port :cc (check-arg cc "cc") :bcc (check-arg bcc "bcc")
:reply-to reply-to
:extra-headers extra-headers
+ :html-message html-message
:display-name display-name
:authentication authentication
:attachments (check-arg attachments "attachments")
@@ -76,56 +79,64 @@
(defun send-smtp (host from to subject message
- &key (port 25) cc bcc reply-to extra-headers
+ &key (port 25) cc bcc reply-to extra-headers html-message
display-name authentication attachments buffer-size)
- (let ((sock (usocket:socket-stream (usocket:socket-connect host port)))
- (boundary (make-random-boundary)))
+ (let* ((sock (usocket:socket-stream (usocket:socket-connect host port)))
+ (boundary (make-random-boundary))
+ (html-boundary (if (and attachments html-message)
+ (make-random-boundary)
+ boundary)))
(unwind-protect
(progn
(open-smtp-connection sock :authentication authentication)
- (write-to-smtp sock
- (format nil "MAIL FROM:~@[~A ~]<~A>" display-name from))
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 250)
- (error "in MAIL FROM command: ~A" msgstr)))
- (compute-rcpt-command sock to)
- (compute-rcpt-command sock cc)
- (compute-rcpt-command sock bcc)
- (write-to-smtp sock "DATA")
- (multiple-value-bind (code msgstr)
- (read-from-smtp sock)
- (when (/= code 354)
- (error "in DATA command: ~A" msgstr)))
- (write-to-smtp sock (format nil "Date: ~A" (get-email-date-string)))
- (write-to-smtp sock (format nil "From: ~@[~A <~]~A~@[>~]"
- display-name from display-name))
- (write-to-smtp sock (format nil "To: ~{ ~a~^,~}" to))
- (when cc
- (write-to-smtp sock (format nil "Cc: ~{ ~a~^,~}" cc)))
- (write-to-smtp sock (format nil "Subject: ~A" subject))
- (write-to-smtp sock (format nil "X-Mailer: cl-smtp ~A"
- *x-mailer*))
- (when reply-to
- (write-to-smtp sock (format nil "Reply-To: ~A" reply-to)))
- (when (and extra-headers
- (listp extra-headers))
- (dolist (l extra-headers)
- (write-to-smtp sock
- (format nil "~A: ~{~a~^,~}" (car l) (rest l)))))
- (write-to-smtp sock "Mime-Version: 1.0")
- (when attachments
- (generate-multipart-header sock boundary))
- (write-char #\Return sock)
- (write-char #\NewLine sock)
- (when attachments
- (setq message (wrap-message-with-multipart-dividers
- message boundary)))
+ (send-smtp-headers sock :from from :to to :cc cc :bcc bcc :reply-to reply-to :display-name display-name :extra-headers extra-headers :subject subject)
+ (send-multipart-headers
+ sock :attachment-boundary (when attachments boundary)
+ :html-boundary html-boundary)
+ ;;----------- Send the body Message ---------------------------
+ ;;--- Send the proper headers depending on plain-text,
+ ;;--- multi-part or html email
+ (cond ((and attachments html-message)
+ ;; if both present, start attachment section,
+ ;; then define alternative section,
+ ;; then write alternative header
+ (progn
+ (generate-message-header
+ sock :boundary boundary :include-blank-line? nil)
+ (generate-multipart-header sock html-boundary
+ :multipart-type "alternative")
+ (write-blank-line sock)
+ (generate-message-header
+ sock :boundary html-boundary :content-type *content-type*
+ :content-disposition "inline" :include-blank-line? nil)))
+ (attachments
+ (generate-message-header
+ sock :boundary boundary
+ :content-type *content-type* :content-disposition "inline"
+ :include-blank-line? nil))
+ (html-message
+ (generate-message-header
+ sock :boundary html-boundary :content-type *content-type*
+ :content-disposition "inline"))
+ (t
+ (generate-message-header sock :content-type *content-type*
+ :include-blank-line? nil)))
+ (write-blank-line sock)
(write-to-smtp sock message)
+ (write-blank-line sock)
+ ;;---------- Send Html text if needed -------------------------
+ (when html-message
+ (generate-message-header
+ sock :boundary html-boundary
+ :content-type "text/html; charset=ISO-8859-1"
+ :content-disposition "inline")
+ (write-to-smtp sock html-message)
+ (send-end-marker sock html-boundary))
+ ;;---------- Send Attachments -----------------------------------
(when attachments
(dolist (attachment attachments)
(send-attachment sock attachment boundary buffer-size))
- (send-attachments-end-marker sock boundary))
+ (send-end-marker sock boundary))
(write-char #\. sock)
(write-char #\Return sock)
(write-char #\NewLine sock)
@@ -190,6 +201,49 @@
(when (/= code 250)
(error "wrong response from smtp server: ~A" msgstr))))))
+(defun send-smtp-headers (sock
+ &key from to cc bcc reply-to
+ extra-headers display-name subject)
+ (write-to-smtp sock
+ (format nil "MAIL FROM:~@[~A ~]<~A>" display-name from))
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp sock)
+ (when (/= code 250)
+ (error "in MAIL FROM command: ~A" msgstr)))
+ (compute-rcpt-command sock to)
+ (compute-rcpt-command sock cc)
+ (compute-rcpt-command sock bcc)
+ (write-to-smtp sock "DATA")
+ (multiple-value-bind (code msgstr)
+ (read-from-smtp sock)
+ (when (/= code 354)
+ (error "in DATA command: ~A" msgstr)))
+ (write-to-smtp sock (format nil "Date: ~A" (get-email-date-string)))
+ (write-to-smtp sock (format nil "From: ~@[~A <~]~A~@[>~]"
+ display-name from display-name))
+ (write-to-smtp sock (format nil "To: ~{ ~a~^,~}" to))
+ (when cc
+ (write-to-smtp sock (format nil "Cc: ~{ ~a~^,~}" cc)))
+ (write-to-smtp sock (format nil "Subject: ~A" subject))
+ (write-to-smtp sock (format nil "X-Mailer: cl-smtp ~A"
+ *x-mailer*))
+ (when reply-to
+ (write-to-smtp sock (format nil "Reply-To: ~A" reply-to)))
+ (when (and extra-headers
+ (listp extra-headers))
+ (dolist (l extra-headers)
+ (write-to-smtp sock
+ (format nil "~A: ~{~a~^,~}" (car l) (rest l)))))
+ (write-to-smtp sock "Mime-Version: 1.0"))
+
+(defun send-multipart-headers (sock &key attachment-boundary html-boundary)
+ (cond (attachment-boundary
+ (generate-multipart-header sock attachment-boundary
+ :multipart-type "mixed"))
+ (html-boundary (generate-multipart-header
+ sock html-boundary
+ :multipart-type "alternative"))
+ (t nil)))
(defun compute-rcpt-command (sock adresses)
(dolist (to adresses)
@@ -198,7 +252,6 @@
(read-from-smtp sock)
(when (/= code 250)
(error "in RCPT TO command: ~A" msgstr)))))
-
(defun write-to-smtp (sock command)
(print-debug (format nil "to server: ~A" command))
@@ -207,6 +260,11 @@
(write-char #\NewLine sock)
(force-output sock))
+(defun write-blank-line (sock)
+ (write-char #\Return sock)
+ (write-char #\NewLine sock)
+ (force-output sock))
+
(defun read-from-smtp (sock)
(let* ((line (read-line sock))
(response-code (parse-integer line :start 0 :junk-allowed t)))
@@ -214,7 +272,7 @@
(if (= (char-code (elt line 3)) (char-code #\-))
(read-from-smtp sock)
(values response-code line))))
-
+
(defun get-email-date-string ()
(multiple-value-bind (sec min h d m y wd) (get-decoded-time)
(let* ((month (elt '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") (- m 1)))
@@ -224,8 +282,7 @@
(get-universal-time)))))
(format nil "~A, ~2,'0d ~A ~d ~2,'0d:~2,'0d:~2,'0d ~D"
weekday d month y h min sec timezone))))
-
-
+
(defun get-timezone-from-integer (x)
(let ((min (/ x 60))
(hour (/ x 3600)))
--- /project/cl-smtp/cvsroot/cl-smtp/mime-types.lisp 2007/11/03 23:53:29 NONE
+++ /project/cl-smtp/cvsroot/cl-smtp/mime-types.lisp 2007/11/03 23:53:29 1.1
;;; -*- mode: Lisp -*-
;;; This file is part of CL-SMTP, the Lisp SMTP Client
;;; Copyright (C) 2004/2005/2006/2007 Jan Idzikowski
;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the Lisp Lesser General Public License
;;; (http://opensource.franz.com/preamble.html) known as the LLGPL.
;;; This library is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; Lisp Lesser GNU General Public License for more details.
;;; File: attachments.lisp
;;; Description: encoding and transmitting login to include a mime attachment
;;;
;;; Contributed by Brian Sorg
;;;
(in-package :cl-smtp)
(eval-when (:compile-toplevel :load-toplevel)
;;; Some of the most common file extensions with the mime types and descriptions.
;;; Extracted from numberous webpages.
(defparameter *mime-type-descriptions*
'(("386" "application/octet-stream"
"Windows Enhanced Mode Driver or Swap File")
("001" "application/x-001" "FAX Datafile")
("3GPP" "audio/3gpp"
"3rd
Generation Partnership Project. Multimedia over 3rd generation wireless
networks. H.263 video is the mandatory video format in 3GPP and AMR is
the main audio/speech format.")
("7CB" "application/vnd.ecdis-update"
"Electronic Chart Display and Information System (ECDIS)")
("aa" "audio/audible" "Audible file format (audio books)")
("aab" "application/x-authorware-bin" "Macromedia Authorware Binary")
("aac" "audio/aac"
"Advanced Audio Coding File. Part of MPEG-2 and MPEG-4 standard. (Apple iTunes Store)")
("aam" "application/x-authorware-map" "Authorware Map (Shockwave?)")
("aas" "application/x-authorware-seg"
"Authorware Shocked Packet (Segment) ")
("aba" "text/x-palm-aba" "AddressBook Archive (Palm)")
("ac3" "audio/ac3"
"Adaptive Transform Coder 3 (relates to the bitstream format of Dolby Digital)")
("adr" "application/x-msaddr" "Address Book")
("aexpk" "application/pgp-keys" "Armored extracted public key (PGP)")
("afl" "video/animaflex" "Font file (for Allways) (Lotus 1-2-3)")
("ahtml" "magnus-internal/cgi-advertiser" " ")
("ai" "application/postscript"
"Encapsulated PostScript (metafile) (Adobe Illustrator)")
("aif" "audio/x-aiff" "Audio Interchange File Format")
("aifc" "audio/x-aiff" "Audio Interchange File Format")
("aiff" "audio/x-aiff" "Audio Interchange File Format")
("aim" "application/x-aim" "AIM file - AOL Instant Messanger")
("alt" "application/x-up-alert" "Menu file (WordPerfect Library)")
("aos" "application/x-nokia-" "Add-On Software (Nokia 9000)")
("arj" "application/x-arj"
"Compressed file archive created by ARJ or winzip")
("art" "image/x-jg"
"AOL Johnson-Grace Compressed File and Another Ray Tracer Format")
("asc" "application/pgp-encrypted" "Armored Encrypted file (PGP)")
("asd" "application/astound" "Autosave file (Word for Windows)")
("asf" "application/vnd.ms-asf video/x-ms-asf video/x-ms-wm"
"Windows Media file - Advanced Streaming Format (ASF), NetShow")
("asn" "application/astound" " ")
("asp" "text/html"
"Active Server Pages - standard HTML documents interlaced with ActiveX script code ")
("asr" "video/x-ms-asf" "Microsoft NetShow")
("asx" "video/x-ms-asf application/x-mplayer2"
"VXtreme (Microsoft streaming AV)")
("asz" "application/astound" " ")
("au" "audio/basic" "8-bit u-law [PCM] / 8000 Hz")
("avi" "video/x-msvideo" "Windows Video file")
("axs" "application/olescript" " ")
("bas" "text/plain" "BASIC program")
("bat" "application/octet-stream" "DOS BAT (Batch) file.")
("bcpio" "application/x-bcpio" "Old Binary CPIO")
("bexpk" "application/pgp-keys" "binary extracted public key (PGP)")
("bin" "application/octet-stream" "Uninterpreted Binary Data")
("bk" "application/vnd.framemaker" "FrameMaker book ")
("bleep" "application/bleeper" " ")
("bmp" "image/x-bmp" "Windows Bitmap (PaintBrush)")
("btf" "image/prs.btf" "NationsBank Check Images (also .btif)")
("c" "text/plain" "C program")
("c++" "text/plain" "C program")
("cab" "application/cab"
"Cabinet file Microsoft installation archive. opersyss=win32, mac cpu=x86, ppc, mips, alpha")
("cal" "application/x-msschedplus" "MS schedplus or calendar")
("cat" "application/pdf"
"PDF Catalog (Used with Acrobat Reader and Search plug-in)")
("cat" "application/vnd.ms-pki.seccat" "Security Catalog")
("ccs" "text/ccs"
"Cluster Configuration System used with the Global File System (GFS) in Red Hat Linux")
("cdda" "audio/aiff" "CD Audio Track")
("cda" "audio/x-cda" "CD Audio Track")
("cdf" "text/plain" "Channel Definition Format - MS push std")
("cdr" "application/x-coreldrw" "Corel Draw (metafile)")
("cer" " application/pkix-cert" "Certificatefile")
("cfm" "wwwserver/wsapi" "Cold Fusion Markup")
("cgi" "magnus-internal/cgi" "Common Gateway Interface")
("cgm" "image/cgm" "Computer Graphics Metafile ")
("chat" "application/x-chat" " ")
("che" "application/x-up-cacheop" " ")
("cht" "audio/x-dspeech"
"Chart (Harvard Graphics 2.0 - SoftCraft Presenter)")
("cil" "application/vnd.ms-artgalry" "Clip Gallery Download Packages")
("class" "application/java-vm" "Java")
("cli" "application/vnd.ms-artgalry" " ")
("clp" "application/x-msclip" "Windows Clipboard (metafile)")
("cmx" "image/x-cmx" " ")
("cnc" "application/x-cnc" "CNC general program data")
("cod" "image/cis-cod"
"Datafile (Forecast Plus - MS Multiplan - StatPac Gold)")
("coda" "application/x-coda" " ")
("com" "application/octet-stream"
"DOS COM Executable (similar to exe, but a direct memory image)")
("cpi" "image/cpi" "ColorLab Processed Image ")
("cpio" "application/x-cpio" "IEEE Std1003.2 (`POSIX') CPIO")
("cpt" "application/mac-compactpro" "Compact Pro Archive")
("crd" "application/x-mscardfile" "MS cardfile")
("crt" "application/x-x509-ca-cert" "Certificatefile")
("csh" "application/x-csh" "CSH Script")
("csm" "application/x-cu-seeme" "Precompiled headers (Borland C++ 4.5)")
("css" "text/css" "Cascading Style Sheets")
("csv" "text/csv"
"Comma-Separated Values (Excel, Lotus 123, FoxPro, MS Outlook)")
("ct" "image/" "Iris CT Graphic or Scitex CT Handshake Bitmap ")
("cu" "application/x-cu-seeme" " ")
("cut" "image/x-halo-cut" "Bitmap graphics")
("dat" "application/octet-stream"
"Data file. Can be anything, text, graphics, binary, ...")
("dba" "text/x-palm-dba" "DateBook Archive (Palm)")
("dbf" "application/octet-stream" "DataBase File (FoxPro, dBase) ")
("dbm" "wwwserver/wsapi" "ColdFusion IIS Plugin")
("dca" "application/dca-rft" "IBM Doc Content Arch")
("dcr" "application/x-director" "Macromedia Director (Shockwave)")
("deb" "application/octet-stream" "Binary for debian UNIX")
("der" "application/x-x509-ca-cert" "Certificatefile")
("dir" "application/x-director" "Macromedia Director (Shockwave)")
("dll" "application/x-msdownload"
"Dynamically Linked Library (DOS) pe-portable executable opersys=win32, mac cpu=x86, ppc, mips, alpha")
("dms" "application/octet-stream"
"Compressed Amiga file archive created by DISKMASHER")
("doc" "application/msword" "MS Word")
("dot" "application/msword" "MS Word (Template)")
("dsf" "image/x-mgx-dsf" "Micrografx Designer 6 (metafile)")
("dst" "application/tajima" "PC-RDist Distribution file ")
("dtd" "text/xml" "SGML Document (Type) Definition file")
("dus" "audio/x-dspeech" "Readiris font dictionary")
("dvi" "application/x-dvi" "TeX DVI (Device Independent)")
("dwc" "application/dwc" "compressed archive")
("dwf" "drawing/x-dwf" "Autodesk WHIP! Drawing Web file")
("dwg" "application/x-acad" "AutoCAD Drawing")
("dxf" "application/vnd.dxf"
"Drawing eXchange Format, Data Exchange File, AutoCAD (vector)")
("dxr" "application/x-director" "Macromedia Director (Shockwave)")
("ebk" "application/x-expandedbook" " ")
("emf" "image/x-emf"
"Enhanced metafile created in Microsoft Windows and Visio 2002 applications")
("eml" "message/rfc822"
"MS Internet Mail Message (Outlook Express and others)")
("enc" "application/pre-encrypted"
"Pre-encrypted Data (also Sniffer trace)")
("eps" "application/postscript" "Encapsulated PostScript (raster)")
("erf" "application/x-hsp-erf" " ")
("es" "audio/echospeech" " ")
("etf" "image/x-etf" "Enriched Text file")
("etx" "text/x-setext" "Structure Enchanced Text")
("evy" "application/x-envoy" "Document (WordPerfect Envoy)")
("exe" "application/x-pe-"
"pe-portable executable opersys=win32, mac cpu=x86, ppc, mips, alpha")
("fdf" "application/vnd.fdf" "acrobat reader")
("fh4" "image/x-freehand" "Vector graphics (Aldus FreeHand 4.x)")
("fh5" "image/x-freehand" "Freehand 5")
[378 lines skipped]
1
0